Effective Objective-C 2.0读书笔记(5)
第五章 内存管理
第二十九条:理解引用计数
-
引用计数的原理
image.png
最终当保留计数归零时,对象就回收了,也就是说,系统会将其占用的内存标记为“可重用”,此时所有指向该对象是我引用也都变得无效了。
一般调用完release之后都会清空指针,这样就能保证不会出现“悬挂指针”(指向无效对象的指针)。
NSNumber * number = [[NSNumber alloc] initWithInt:123];
[number release];
number = nil;
- 属性存取方法中的内存管理
此方法将保留新值 并 释放旧值,然后跟新实例变量,令其指向新值。顺序很重要
- (void)setFoo:(id)foo{
[foo retain];
[_foo release];
_foo = foo;
}
*自动释放池
autorelease 此方法会在稍后递减计数,通常是下一次“事件循环”时递减
- (NSString *)stringVaule{
NSString * str = [[NSString alloc] initWithFormat:@"haha"];
return [str autorelease];
// autorelease能延长对象生命周期,使其在跨越方法调用边界后 依然可以存活一段时间。
}
*保留环
呈环状 相互引用的对个对象。导致内存泄漏。
解决方法:
(1)“弱引用”;
(2)令循环中的某个对象不再保留另一个对象;
- 引用计数机制 通过可以递增递减的计数器来管理内存。
对象创建好之后,其保留计数至少为1,若保留计数为正,则对象存活,为0对象就被销毁了。
- 在对象生命期中,其余对象通过引用来保留或者释放此对象。保留与释放操作分别会递增递减保留计数。
第三十条 :以ARC 简化引用计数
ARC会用一种安全的方式来设置:先保留新值,在释放旧值,最后设置啊实例变量。
- (void)setup{
id tmp = [EOCOtherClass new];
_object = [tmp retain];
[tmp release];
}
- 可以用修饰符来 改变局部变量与实例变量的语义:
- __strong :默认语义,保留此值。
- __unsafe_unretained: 不保留此值,这么做可能不安全,因为等到再次使用变量时,其对象可能已经回收了。
- __weak: 不保留此值,但是变量可以安全的使用,因为如果系统把这个对象回收了,那么变量也会自动清空。
- __autoreleasing: 把对象“按引用传递”给方法时,使用这个特殊的修饰符,此值在方法返回时自动释放。
第三十一条:在dealloc方法中只释放引用并解除监听
执行异步任务的方法不应该在dealloc里调用;只能在正常状态下执行的那些方法也不应该在dealloc里调用,因为此时对象已经处于正在回收的状态了。
第三十二条:编写“异常安全代码”时留意内存管理问题
-
在Objective-C代码中,只有当应用程序必须因异常状况而终止时才应抛出异常。因此还去添加 安全处理异常所用的附加代码是没有意义的。
-
在默认情况下,ARC不生成安全处理异常所需要的清理代码,
-
若要使用ARC且必须捕获异常,则需要打开编译器 -fobjc-arc-exceptions标志。开启后可生成这种代码,不过 会导致应用程序变大,而且会降低运行效率。
第三十三条:以弱引用 避免保留环
image.png第三十四条:以“自动释放池块”降低内存峰值
Objective-C对象的生命周期取决于 其引用计数。
释放对象的两种方式:
(1)release 引用计数减一。
(2)autorelease 在稍后某个时刻释放对象。
// 创建自动释放池(轻量级)
@autoreleasepool{
// ...
}
系统会自动创建一些线程,比如主线程和GCD机制中线程,这些线程默认都有自动释放池,每次执行“事件循环”时,就会将其清空。
-
内存峰值:是指应用程序在某个特定的时段内的最大内存用量。新增的自动释放池块可以减少这个峰值,因为系统会在块的末尾把某些对象回收掉。
-
NSAutoreleasePool对象:专门用来表示自动释放池,通常用来创建那种偶尔需要清空的池。
-
自动释放池排布在栈中,对象收到autorelease消息后,系统将其放入最顶端的池里。
第三十五条:用“僵尸对象”调试内存管理问题
向已经回收的对象发送消息是不安全的,取决于 对象所占内存有没有为其他内容所覆写。
运行期系统会把所有已经回收的实例转化为特殊的“僵尸对象”,而且不会真正回收他们。
“僵尸对象”所在的 核心内存 无法重用,因此不能覆写。僵尸对象收到消息后,会抛出异常。
将 NSZombieEnabled环境变量 设为YES 开启“僵尸对象”功能。
- 系统会修改对象的isa指针,令其指向特殊的僵尸类,从而使该对象变为僵尸对象。僵尸类能够响应所有的选择子,响应方式为:打印一条包含消息内容及其接收者的消息,然后终止应用程序。
第三十六条:不要使用retainCount
retainCount 是NSObject协议中定义的方法,用于查询对象当前的保留计数。ARC废弃了。
此方法无用的原因:
(1)它所返回的保留计数只是某个给定时间点上的值。未考虑到系统稍后会把自动释放池清空。
(2)retainCount 可能永远不返回0,