可可西

Objective-C内存管理机制概述

Objective-C管理的是分配在堆上的NSObject对象的内存,对其他非对象的C语言数据类型(intcharfloatdoublestructenum等)无效。

有以下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运行时会将引用计数操作retainrelease变为无操作。

当垃圾收集启用时,所有的对象都是收集器的工作对象。使用__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代码(如删除retainrelease调用)。

使用关键字__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的标识。

 

参考

iOS Objective-C 中是否支持垃圾回收机制

 

posted on 2023-10-22 21:07  可可西  阅读(23)  评论(0编辑  收藏  举报

导航