如果在网上搜关于内存管理最多的总结就是谁持有谁释放。但是内存管理往多的说是有好多东西的,我今天只写一下关于strong、weak和autoreleas(以后会写片博客,会介绍到它们的底层运作)。在此也给想更深入了解的伙伴们推荐本书一个日本前辈写的Objective-C高级编程,我自己讲内存管理梳理的差不多清晰的时,多亏了它。
关于内存管理,我原来有一段时间都对strong、weak傻傻的区分不清楚,也没有多少兴趣去了解。直到一天我真的在使用代理中碰到了神奇的内存泄漏,害死我了,经过调查锁定了凶手就是weak,根本的罪魁祸首是我对修饰符使用的一知半解。希望这点理解能起到一点点帮助。
a、区分strong、weak
strong:strong为强引用,是id类型对象和对象默认的所有权修饰符(我们平时在@property中指定了属性的修饰strong、weak、或者是assign,但是在创建其他对象的时候,系统帮我们默认加了_strong修饰符进行内存管理),使用strong修饰的对象在超出其变量作用域时,即该变量被废弃时,会释放其被赋予的对象。使用strong会对对象被持有对象的引用计数产生影响,当其持用一其他对象的时候,会将其他对象的引用计数加1,当出作用域强引用失效时,会释放掉对其持有对象的持有。
weak:weak为若引用。weak修饰的对象,当其持有其他对象的时候不会对其他对象的引用计数造成影响,weak的存在很好的解决掉了循环引用。当它所持有的对象销毁时,weak修饰的对象会自动置nil。关于weak的实现我简单的多说一点,因为我自己原来对此很好奇然后多方了解了下,在此分享给大家,如果有错欢迎更希望大家纠正。
runtime会对注册的类进行布局,对于weak对象会放入一个hash表中。使用weak对象的内存地址作为key,当weak对象指向的对象的引用计数为0的时候执行置nil。执行过程为以weak对象的内存地址为索引,在hash表中找到对应的weak修饰对象,将其置为nil。
b、作用的区分
讨论他两避免不了循环引用和自引用。说白了就是光使用strong容易出现内存泄漏即在对象出了作用域(也就是大括号)后不能得到释放。如下例子:
分别创建对象a、b,他们分别被对象A、B持有(当我们没有指定修饰权时,我们创建的对象默认的修饰权为_strong,也就是强引用)。然后对象B中有个成员变量objB又持有了a一次,对象A中的成员变量abjA有持有了b一次。这样,就会形成循环引用。因为在出了作用域后A、B的强引用失效,释放掉了对a、b的持有,但是他们中的成员变量并没有释放掉对于a、b的持有。此时发生内存泄漏,也就是我们所说的循环引用。
上面刚刚说过,weak不会对引用计数造成影响,也就不会影响到有关对象的释放。所以我们在关键部位使用weak修饰并不会造成对有关对象的引用计数造成影响,从而使得已经出了作用域但是有关该释放的对象并不能得到释放,造成内存泄漏。
c、autoreleas有关问题
之所以说autoreleas是因为原先在网上学习内存管理这块的时候被误导过,在此希望大家注意。autoreleas释放池中对对象的释放我原来好奇过,上网查的时候最后形成的答案是作用域。但是随着对O-C更加深入的学习,发现了它对于其内部寄存对象的释放是和runloop有关系的。
iOS程序由许多的runloop组成,每一个runloop都会有一个Autorelease Pool并在末尾进行释放。
比如我们点击一个button,一个button从等待到点击到响应就存在一次循环,期间就前程到对象的创建和最后Autorelease Pool在runloop即将结束时的销毁全部对象。
来源:oschina
链接:https://my.oschina.net/u/2814714/blog/716688