据说ObjC三大难点之一就有内容管理,这项比较有趣的内容终于来临了!Come on~

1.自动释放池

在处理Foundation程序时,为了使用Foundation对象,必须设置自己的池。系统使用这个池来跟踪对象,以便以后释放。在应用程序中,可以通过调用来建立这个池。

如:NSAutoreleasePool * pool=[[NSAutoreleasePool alloc]init];

建立了自动释放池之后,Foundation将自动为这个池添加数组、字符串、字典等对象,使用完该池后调用drain来释放它的内存,如:[pool drain];

也可以通过像当前的自动释放池发送一条autorelease的消息,将对象加入自动释放池中,这样对象会在自动释放池释放时释放掉对象本身的内存。

当程序产生大量的临时对象是,可能需要在程序中创建多重自动释放池,如:

   NSAutoreleasePool *tempPool;for (int i = 0; i < 10; i++) {tempPool = [[NSAutoreleasePool alloc] init];NSString *string = [NSString stringWithString:@"ABC"];string = [string lowercaseString];string = [string stringByAppendingString:@"XYZ"];NSLog(@"%@",string);[tempPool drain];}

自动释放池实例:需应用NSObject及NSAutoreleasePool

@interface Foo:NSObject
{int x;
}
@end@implementation  Foo
@end
    NSAutoreleasePool *p = [[NSAutoreleasePool alloc]init];Foo *f = [[Foo alloc]init];NSLog(@"%x",[f retainCount]);//init[p drain];NSLog(@"%x",[f retainCount]);//p drainp = [[NSAutoreleasePool alloc]init];[f autorelease];NSLog(@"%x",[f retainCount]);//p init f autorelease[f retain];NSLog(@"%x",[f retainCount]);//f reatin[p drain];NSLog(@"%x",[f retainCount]);//p drain[f release];

结果输出:

2013-06-03 01:36:59.365 Test[904:c07] 1

2013-06-03 01:36:59.367 Test[904:c07] 1

2013-06-03 01:36:59.368 Test[904:c07] 1

2013-06-03 01:36:59.369 Test[904:c07] 2

2013-06-03 01:36:59.370 Test[904:c07] 1

由此我们可以知道当添加了autorelease后的池被释放时会向对象发送release消息~但我们最后仍需手动释放对象避免内存泄漏。

2.计数

计数这个概念是当对象被多个地方引用,而确不知道它到底工作完没有,这时候我们如果把它释放了后面引用到它的必将出现错误,所以引入了计数这样得概念。

创建对象时,计数会自动设置为1,也可以用使用retain对其计数加1,而当我们调用release时,对象得引用次数会减1.我们可以通过retainCount获得对象得引用计数。

代码实例:

NSNumber *myInt =[NSNumber numberWithInteger:100];NSNumber *myInt2;NSMutableArray *arr = [NSMutableArray array];NSLog(@"myInt retain count =%lx",(unsigned long) [myInt retainCount]);//return 0;[arr addObject: myInt ];NSLog(@"afetr adding to arr = %lx",(unsigned long) [myInt retainCount]);myInt2 = myInt;NSLog(@"afetr asssingnment to int2 = %lx",(unsigned long) [myInt retainCount]);[myInt retain];NSLog(@"myInt afetr myInt retain = %lx",(unsigned long) [myInt retainCount]);NSLog(@"myInt2 retain myInt retain = %lx",(unsigned long) [myInt2 retainCount]);[myInt release];NSLog(@"myInt afetr myInt release = %lx",(unsigned long) [myInt retainCount]);[arr removeObjectAtIndex:0];NSLog(@"myInt afetr arr remove = %lx",(unsigned long) [myInt retainCount]);

结果:

2013-06-02 15:30:44.652 Test[614:c07] myInt retain count =1

2013-06-02 15:30:44.654 Test[614:c07] afetr adding to arr = 2

2013-06-02 15:30:44.656 Test[614:c07] afetr asssingnment to int2 = 2

2013-06-02 15:30:44.658 Test[614:c07] myInt afetr myInt retain = 3

2013-06-02 15:30:44.660 Test[614:c07] myInt2 retain myInt retain = 3

2013-06-02 15:30:44.662 Test[614:c07] myInt afetr myInt release = 2

2013-06-02 15:30:44.664 Test[614:c07] myInt afetr arr remove = 1

myInt 开始初始化后计数就变为1;

添加到数组中引用次数随之变为2;

接下来,将myInt赋值给变量myInt2这个操作并没有使myInt对象得引用次数增加,那么myInt赋值给myInt2时并没有复制实际得对象只是让myInt2指向myInt的内存指针,所以当myInt的引用计数减少到0时,myInt2将拥有无效的对象引用;

之后就时retain让对象计数增加,release让对象计数减少,remove让对象计数再减少~

* 补充一点需要注意的:NSString 对象在内存中常量字符串的空间分配与其他对象不同,它们没有引用计数机制,因为永远不能释放这些对象,向NSString对象发送消息retainCount,它会返回0xffffffff;

代码实例2:

@interface ClassAA :NSObject
{NSString *str;
}
-(void) setStr:(NSString *)s;
-(NSString *) str;
@end@implementation ClassAA
-(void) setStr:(NSString *)s
{str = S;//[str retain];
}
-(NSString *)str
{return str;
}
@end
    ClassAA *ca = [[ClassAA alloc]init];NSLog(@"%x",[ca retainCount]);[ca setStr:@"11"];NSLog(@"%x",[ca retainCount]);

结果:

2013-06-03 01:10:12.681 Test[866:c07] 1

2013-06-03 01:10:12.684 Test[866:c07] 1

如上程序有缺陷。

而如果把setStr中的注视去掉 那么结果就是 1 2

这样以后别的代码调用释放引用时,程序将不会收到影响因为计数不一样了。

我们也可以重写类的dealloc方法,让它release变量及super dealloc。

Cocoa内存管理规则

Cocoa内存管理原则很简单:

  • 当使用new,alloc或者copy方法创建对象的时候,该对象计数器为1。当不在使用的时候,要release释放该对象或者autorelease提交到对象自动释放池。
  • 当通过其他方法获得对象,要假设该对象的计数器已经是1,而且被设置autorelease了。在获得该对象后不需要进行清理操作。如果打算使用一段时间,需要retain操作,并且在使用完毕做release释放它。
  • 如果retain了某个对象。需要release或者autorelease该对象。并且保持retain和release方法调用的次数一样多。

举一个常见的例子。比如使用NSArray:

int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];Author *author=[[Author alloc]init]; NSArray *array=[NSArray arrayWithObjects:author,nil]; NSLog(@"author retain count: %i",[author retainCount]); [author release]; NSLog(@"author retain count: %i",[author retainCount]); [pool drain]; return 0;
}

这里创建了一个author对象,并且把它放到NSArray中去了。当放入NSArray后,会发现author的引用计数为2了,也就是说在放入集合中后,引用计数会自动加1。

另外,array变量不是通过new、alloc或者copy创建的,因此我们假设(实际上就是)它会retain使引用计数为1了。而且还是autorelease的。因此上面的例子并未release array。

-----------------------

摘一段总结:

内存管理关心的是清理(回收)不用的内存,以便内存能够再次利用。

提供给Objective-C程序员的基本内存管理模型有以下三种:

1)自动垃圾收集。(iOS运行环境并不支持垃圾收集,在这个平台开发程序时没有这方面的选项,只能用在Mac OS X 程序上开发。这个机制挺恶心的,用mac电脑的人知道,当内存不足的时候,机器基本上就是卡死了。)

2)手工引用计数和自动释放池。(这种方式,对程序员的要求很高。自己维护嘛,)

3)自动引用计数(ARC)。

手工内存管理规则的总结:

1)如果需要保持一个对象不被销毁,可以使用retain。在使用完对象后,需要使用release进行释放。

2)给对象发送release消息并不会必须销毁这个对象,只有当这个对象的引用计数减至0时,对象才会被销毁。然后系统会发送dealloc消息给这个对象用于释放它的内存。

3)对使用了retain或者copy、mutableCopy、alloc或new方法的任何对象,以及具有retain和copy特性的属性进行释放,需要覆盖dealloc方法,使得在对象被释放的时候能够释放这些实例变量。

4)在自动释放池被清空时,也会为自动释放的对象做些事情。系统每次都会在自动释放池被释放时发送release消息给池中的每个对象。如果池中的对象引用计数降为0,系统会发送dealloc消息销毁这个对象。

5)如果在方法中不再需要用到这个对象,但需要将其返回,可以给这个对象发送autorelease消息用以标记这个对象延迟释放。autorelease消息并不会影响到对象的引用计数。

6)当应用终止时,内存中的所有对象都会被释放,不论它们是否在自动释放池中。

7)当开发Cocoa或者iOS应用程序时,随着应用程序的运行,自动释放池会被创建和清空(每次的事件都会发生)。在这种情况下,如果要使自动释放池被清空后自动释放的对象还能够存在,对象需要使用retain方法,只要这些对象的引用计数大于发送autorelease消息的数量,就能够在池清理后生存下来。

自动引用计数(ARC):

强变量,通常,所有对象的指针变量都是强变量。

如果想声明强变量,可以使用__strong Faction *fl;这样的__strong来修饰。

值得注意的是,属性默认不是strong,其默认的特性是unsafe_unretained类似assign。所以需要声明属性strong时,可以如下:

@property (strong, nonatomic) NSMutableArray *birdNames;

编译器会保证在事件循环中通过对赋值执行保持操作强属性能够存活下来。带有unsafe_unretained(相当于assign)或weak的属性不会执行这些操作。

弱变量,可以使用__week关键字来声明。弱变量不能阻止引用的对象被销毁。当引用的对象释放时,弱变量会被自动设置为nil。

需要注意的是,在iOS4和Mac OS V10.6中不支持弱变量。在这种情况下,你仍然可以为属性使用unsafe_unretained, assing特性.

ARC都会在“底层”发生,所以一般不用关心。




ObjC学习10-Foundation框架之内存管理相关推荐

  1. C/C++学习之路_七: 内存管理

    C/C++学习之路_七: 内存管理 目录 作用域 内存布局 内存分区代码分析 1. 作用域 C语言变量的作用域分为: 代码块作用域(代码块是{}之间的一段代码) 函数作用域 文件作用域 1. 局部变量 ...

  2. Objective-C基础教程学习笔记(九)内存管理

    每个对象都维护一个保留计数器.对象被创建时,其保留计数器值1:对象被保留时,保留计数器值加1:对象被释放时,保留计数器值减1:当保留计数器值归0时,对象被销毁.在销毁对象时,首先调用对象的deallo ...

  3. C++学习笔记-DLL中动态内存管理

    动态内存管理 在dll中malloc的内存,必须在dll中free 注:这是由Windows自己的特点决定! 如果 a 编译成静态库,有下面两种解决方法: 1.b.dll 和 c.dll 使用同一个款 ...

  4. Linux驱动学习12(初步认识内存管理)

    一.MMU的基本知识 1.内存管理单元简称mmu,她负责虚拟地址到真实物理地址的转换,并且提供了硬件机制以检查内存 访问权限,同时对Cache缓存进行控制. 2.现代计算机多进程操作系统通过mmu使得 ...

  5. 【JVM高级特性与最佳实践(第3版)-周志明】-学习记录之【自动内存管理】

    写在前面,不是原创,是周志明老师书里得内容,方便个人随时学习查看,因为发布得时候没有这个选项,只能选原创 一.概述 对于Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每一个new操作 ...

  6. WSF操作系统抽象层学习笔记 (一) ---简介和内存管理

    一.简介 WSF(wireless software foundation)是对操作系统的一个简单的封装,提供对操作系统的简单编程,提供简单的系统服务 功能简介: 事件.消息传递和处理. 定时器功能. ...

  7. mysql内存管理,学习猿地-闲谈 MySQL内存管理,内存分配器和操作系统

    当用户使用任何软件(包括MySQL)碰到内存问题时,我们第一反应就是内存泄漏.正如这篇文章所示,其实并不总是这样. 这篇文章阐述一个关于内存的bug. All Percona Support cust ...

  8. 《深入理解JAVA虚拟机》学习日志----一、自动内存管理机制(2.垃圾收集器与内存分配策略)

    二.垃圾收集器与内存分配策略 前言:讨论的区域集中在Java堆和方法区中,而其他几个区域的内存分配和回收都具备确定性,所以不需过多考虑回收 的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了. ...

  9. C语言深度剖析书籍学习记录 第五章 内存管理

    常见的内存错误 定义了指针变量,但是没有为指针分配内存,即指针没有指向一块合法的内存. 结构体成员指针未初始化 很多初学者犯了这个错误还不知道是怎么回事.这里定义了结构体变量 stu,但是他没 想到这 ...

最新文章

  1. 新版GNS3-安装及配置教程
  2. SpringBoot笔记:SpringBoot2.3集成SpringSession+nginx+redis实现session共享
  3. ElementUI el-time-picker-只显示小时、分钟,分并添加范围校验
  4. SpringMVC接收哪些类型参数参数
  5. [导入]New ASP.NET Charting Control: asp:chart runat=server/
  6. Spring Cloud Alibaba | Dubbo 与 Spring Cloud 完美结合
  7. sample_venc解析
  8. 【阿里云镜像】配置阿里云Maven 镜像
  9. Code33 整数转罗马数字
  10. 如何将图片转成png格式?图片的格式怎么转换
  11. You hasn‘t joined this enterprise!
  12. 云计算的三种服务模式的讲解
  13. GoDEX条码打印机批量打印条码设置
  14. CTFHub题解-技能树-Misc-流量分析-数据库类流量【MySQL流量、Redis流量、MongoDB流量】
  15. 工程建设项目综合信息管理系统
  16. table.getn(tableName) 的用法注意。
  17. 基于ZYNQ 7000的1553B总线控制器测试系统的设计与实现
  18. Internet Explorer 8
  19. 如何在 Virtual Box 上下载 Docker
  20. [LiteratureReview]CubeSLAM Monocular 3-D Object SLAM

热门文章

  1. android mm 修改路径,Android 编译系统模块
  2. 计算机专业马来西亚,去马来西亚读计算机专业如何
  3. 企业全面运营管理沙盘模拟心得_大庆职业学院举办创业技能大赛企业经营管理沙盘模拟赛...
  4. 外贸常用术语_外贸常用贸易术语之间,要这么换算……
  5. arcgis运行慢_ArcGIS Pro运行较慢的诊断方法
  6. mysql是否需要设置外键_数据库到底需不需要设置外键?
  7. php 动态多维数组长度,php – 动态创建多维数组
  8. 鸟哥Linux计算退伍时间,发现《鸟哥的Linux基础篇》中有个脚本还能再完善点。...
  9. 显示not_Excel函数06:逻辑函数之OR、NOT函数应用实例分析
  10. MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications