iOS 对象的内存管理

698 阅读4分钟

对象的内存管理方式

1.MRC:手动引用计数,手动retain和release引用计数。

2.ARC:自动引用计数,LLVM编译器帮助我们管理引用计数。(合适的地方写入retain,copy,release,autorelease)

关于MRC需要了解的知识点

1.引用计数机制通过可以递增递减的计数器来管理内存,对象创建好后,其保留计数至少为1。若保留计数为正,则对象继续存活。当保留计数为0时,对象就销毁了。

2.在对象生命周期中,其余对象通过引用来保留或释放此对象。保留与释放操作分别会递增及递减保留计数。

我们通过retain来增加计数,release来减少计数,但是在return的函数当中,我们不希望当前创建的对象销毁,而是希望把它return出去,此时可以通过[object autorelease]来延长object的生命周期,object会在返回地址所在函数的自动释放池销毁,调用autorelease后对象的retaincount不会减1,故retaincount对引用计数的描述是不准确的。

{

​     _object;

}

(void)setObject:(id)object{

​    [_object release];

​    [object retain];

}

关于ARC需要了解的知识点

1.ARC管理对象的办法基本就是:编译器会在合适的地方写入保留和释放操作,变量的内存管理语义可以通过修饰符指明(@property在ARC下的默认的修饰符:atomic,readwrite,assign(为非对象时)或strong(为对象时),MRC时为atomic,readwrite,assign)

2.由方法所返回的对象,其内存管理语义总是通过方法名来体现(copy,retain,release,autorelease)

3.ARC只负责管理Objective-C对象的内存(CoreFoundation的对象需要程序员手动管理,譬如CFRelease,CFRetain)

4.在dealloc中我们该做的事只应该是释放其他对象的引用,并取消KVO的监听,移除通知,不要在此进行其他操作,因为此对象即将被回收

5.OC一般不考虑异常代码处理,因为一般出现异常应用就崩溃了,所以一般没必要处理异常时的对象回收(但是OC本身可以通过打开编译器的-fobjc-arc-exceptions标志位实现对异常时的对象回收)

6.循环引用的解决办法是一方使用strong指针,另一方使用weak指针(延长weak指针的生命周期的办法是再创建一个strong指针去引用这个weak指针,待新创建的strong指针被回收了,那么原先的两个对象自然会被回收了,block的weakself和strongself就是这样的例子)

7.autoreleasepool可以降低内存峰值,提前释放对象

8.对象的内存被回收后,该对象的地址被标为可用状态,但对象本身依旧在内存中,此时指向该对象的指针叫做野指针,调用野指针的对象可能会获取到对象原先的值,也可能对象所在地址被覆写了新值(因为改地址被标为可用,所以可能被其他新创建的对象占用了),对于野指针,我们需要做的就是将它的值置空,即nil,这样的指针叫空指针。我们可以通过打开xcode编译器的Enable Zombie Objects选项来发现对野指针的调用,即对僵尸对象的调用,我们在DEBUG环境下调试程序的时候,当遇到僵尸对象的调用时,应用会打印错误消息(原理是通过runtime动态添加了一个Zombie+原class名字的新类,但是没有实现原class的方法,此时Zombie新类收到消息时就会执行runtime的消息转发机制,来到动态消息转发时系统打印了当前僵尸对象)

9.OC主要使用的修饰符
9.1 strong:__strong 保留此值
9.2 weak:__weak 不保留值
9.3 retain:__strong 保留此值
9.4 assign:__unsafe__unretain 可以修饰C类型,基本数据类型和对象 不保留值
9.5 copy: __strong 保留此值
9.6 autorelease:__autoreleasing 引用传递,此值在方法返回时自动释放,延长了对象的生命周期

weak和strong替代了以往的assign和retain,现今看到的用assign修饰的变量是为了适配更低版本的iOS系统,建议不保留值得对象用weak。