Objective-C内存管理机制概述
Objective-C管理的是分配在堆上的NSObject对象的内存,对其他非对象的C语言数据类型(int、char、float、double、struct、enum等)无效。
有以下3种方式:
- 手工引用计数和自动释放池(MRC,Manual Reference Counting),又称手动保留释放(MRR,Manual Retain-Release)
- 垃圾收集(GC,Garbage Collection)
- 自动引用计数(ARC,Automatic Reference Counting)
自1980年代Objective-C诞生以来就使用支持MRC(或MRR)。该方式使用引用计数算法来管理内存。retain引用计数+1,release引用计数-1,当引用计数变为0则对象就会被销毁。
在2006年7月苹果全球开发者会议中,Apple宣布了Objective-C 2.0的发布,其增加了垃圾收集(GC)机制。
在2007年10月26日,Mac OS X 10.5 Leopard版本中实现了垃圾回收,在Mac环境提供了一个可选垃圾收集器。注:iOS上的Objective-C 2.0实现中不包含垃圾收集器。
在向后兼容模式中,Objective-C运行时会将引用计数操作retain与release变为无操作。
当垃圾收集启用时,所有的对象都是收集器的工作对象。使用__strong修饰的指针,标记其指向的对象仍在使用中。被标记为__weak的指针不被计入收集器的计数中,并在对象被回收时改写为nil。
垃圾收集器运行在一个低优先级的后台线程中,并可以在用户动作时暂停,从而保持良好的用户体验。
在2012年7月25日,Mac OS X 10.8 Mountain Lion和iOS5中引入了ARC,不再推荐使用GC(甚至声明将在未来版本中弃用GC)。
最后,在2015年5月1日,苹果公司要求所有提交到App Store的Mac App及更新都不允许使用GC。注:详见Mac Apps That Use Garbage Collection Must Move to ARC
主要原因是由于GC过程会导致进程长时间得不到响应,内存不能及时回收导致占用高。
垃圾收集(GC,Garbage Collection)
① 全局变量和静态变量引用的NSObject对象不允许被回收, 栈内临时变量引用的NSObject对象也不允许被回收,这些对象称为根集合。
② 根集合中通过若弱引用连接的实例对象可被回收,并自动置nil。
③ NSObject对象被回收释放前会被执行finalize方法。
void *__strong NSALLocateCollectable(NSUInterger size, NSUInterger options); //根据指针的声明不同 垃圾回收的规则也不同 //p1不是对象类型 被回收后会变成野指针 static void* p1 = NSALLocateCollectable(SZ, opt); //p2是弱指针对象 被回收后会被nil static __weak void* p2 = NSALLocateCollectable(SZ, opt); //p3是强指针对象 不会被回收 static __strong void* p3 = NSALLocateCollectable(SZ, opt);
自动引用计数(ARC,Automatic Reference Counting)
相比MRC,ARC通过编译器代码插入和Runtime支持,让程序员不再需要书写retain/release/autorelease语句。
Xcode 提供了一个迁移工具,可以自动将MRC代码转换为ARC代码(如删除retain和release调用)。
使用关键字__strong代替MRC模式下的retain(代表强引用,引用计数会+1),用__weak来代替MRC模式下的assgin(代表弱引用 注:assign为赋值属性),同时当__weak对象释放后会自动置为nil。
相比垃圾回收,ARC无法处理retaincycles(循环引用):如果两个对象互相强引用(strong references)将导致它们永远不会被释放,甚至没有任何对象引用它们。注:MRC也无法处理retaincycles
因此,尽管ARC能免去程序员大部分内存管理问题,但仍然要程序员自己避免retaincycles或手动打断对象之间的retain循环。
ARC和垃圾回收还有一个重要的不同:ARC不是强制的。而对于苹果的垃圾回收,要么整个程序都使用,要么都不用。
也就是说在app中的所有OC代码,包括所有的苹果框架和所有的第三方库必须支持垃圾回收,才能使用垃圾回收。
相反,ARC和MRC代码可以在一个app中和平共处,支持混编。这使得将项目可以零星地迁移到ARC,而不会像垃圾回收起初遇到的各种兼容性和稳定性的问题。
注:在ARC项目中,对MRC的文件可以添加编译选项-fno-objc-arc的标识;在MRC项目中,对ARC的文件可以添加编译选项 -fobjc-arc的标识。
参考