最近系统地复习了OC的内存管理,所以总结下. OC是通过引用计数(reference count)来管理内存.自从iOS5推出的自动引用计数后,内存管理的工作几乎都是交给编译器,但是详细了解内部机制,无论是对学习一门语言还是在实际项目中防止内存泄露使程序高效运行都至关重要.
内存管理的思考方式:
1.自己生成的对象,自己所持有: 使用alloc ,new, copy, mutableCopy,allocMyObject,newThatObject, copyThis, mutableCopyYourObject 名称开头的方法名生成的对象只有自己持有.
2非自己生成的对象自己也能持有: 利用retain方法能将非自己生成的对象变为自己所持有.
3.不再需要自己持有的对象时释放
4.非自己持有的对象无法释放
理解内存管理及其相关细节:
1.在线程的一次事件循环(even loop)中, 自动释放池(autorelease pool)会被创建和释放,调用autorelease的对象会被放入自动释放池,释放时(drain),会同时释放掉池内的对象,因此调用autorelease的对象其实是延迟释放. 引用一个对象时,其引用计数+1(retain),不需要时(release),当对象的引用计数为0时,对象将被释放(dealoc);
2.NSAutoreleasePool对象不能被autorelease,因为它的autorelease方法已被重载;
3.理解autorelease的实现:利用"IMP Caching"实现提升执行oc方法的速度.
4..用弱引用(weak,unsafe_unretained)防止循环引用:weak和unsafe_unretained都是弱引用,不持有持有对象, 区别在于实例对象的引用移除后,unsafe_unretained仍然指向那个已经回收的实例,而weak属性则指向nil;
5.ARC的好处:除了自动调用保留和释放方法外,可以执行一些手工操作很难甚至无法完成的优化,互相抵消多次的release,autorelease,retain操作; 在方法中返回自动释放的对象时,会执行objc_autoreleaseReturnValue(检测返回之后的代码,若返回的对象会执行retain操作,则设置全局数据结构标志位,不执行autorelease方法,如果发现调用方法的的代码要保留此对象,则不执行retain,改执行objc_retainAutoreleaseReturnValue,此函数会检测标志位,若置位则不执行retain)
6.利用自动释放池块( @autoreleasepool{} )降低内存峰值: 在大量创建临时对象时,这些临时对象会被放入自动释放池延迟释放,而自动释放池会等到线程执行下一次事件循环才会释放,因此内存会呈现持续上涨然后突然下降的的情况,例如在读取大量数据库数据对象,短时间内生成很多图片都会导致此情况,加入自动释放池块可解决此问题.
7.自动释放池排布在栈中,对象收到autorelease方法后放入栈最顶端的池子,@autoreleasepool{}这种新式写法能创建出更为轻便的自动释放池;
8..继续引用(发消息给)已经回收的对象是不安全的。崩溃与否取决于对象所占的内存有没有为其他内容所覆写。
9.启用僵尸对象调试内存管理问题:Scheme ->Run ->Diagnostics,勾选“Enable Zombie Objects”选项。开启之后系统能把已经回收的实例转化为僵尸对象而不会真正回收他们,僵尸对象的核心内存无法被覆写,但收到消息后会抛出异常,说明发来的消息以及描述回收之前的对象。
10..理解僵尸对象的产生过程,基于运行期程序库,Foundation框架及CoreFoundation框架,由僵尸类创建。
11.在arc中.void 和id型或对象变量转换时需要通过"_bridge转换"; __bridge_retained 类似retain,__bridge_transfer 类似 release, oc对象通过(__bridge_retained void*)转换为c语言产生的void *型; 反之,c语言产生的void *型通过(__bridge_transfer)转化为OC对象;
12.CoreFoundataion是C语言编写的库,产生的对象用需要手动释放,CoreFoundataion里的retain/release分别对应是CFRetain/CFRelease, "_bridge转换"中__bridge_retained可以替代CFBridgingRetain,__bridge_transfer替代CFBridgingRelease; Foundataion框架生成并持有的oc对象作为CoreFoundataion对象来使用,可以用CFRelease来释放;
11.dealoc方法:释放对象所拥有的非OC对象例如CoreFoundataion对象; 解除监听(KVO)或者通知; 执行异步任务的方法也不应在dealoc中调用;