自动引用计数(Automatic Reference Counting, ARC)
垃圾收集器:
从Mac OS X 10.8开始,“垃圾收集器”(gargae collector)已经正式废弃了。
每个对象都有个计数器,用以表示当前有多少个事物想令此对象继续存活下去。叫做“保留计数”(retain count),也可以叫“引用计数”(reference count)。
由三个方法操作计数器:
reatain 递增
release 递减
autorelease 递减,自动释放池(autorelease pool,第34条)
查看保留计数的方法:retainCount, 不推荐使用。
对象创建出来时,其保留计数至少为1。
当保留计数为零时,对象就回收了(deallocated),也就是说,系统会将其占用的内存标记为“可重用”(reuse)。
内存在“解除分配”(deallocated)之后,只是放回“可用内存池”(avaiable pool)。如果该内存没有覆写,那么对象仍然有效,这时程序不会崩溃。
为避免在不经意间使用了无效对象,一般调用完饭release之后都会清空指针。这时就能保证不会出现可能指向无效对象的指针,这种指针通常称为“悬挂指针”(dangling pointer,野指针)。
例:
[xxxx release];
xxxx = nil;
对象如果持有指向其他对象的强引用(strong reference),那么前者就“拥有”(own)后者。
引用的“根对象”
MAC OS X应用程序中,NSApplication对象
iOS应用程序中,UIApplication对象。
两者都应用程序启动时创建的单例。
属性存取方法中的内存管理:
例:
-(void)setFoo:(id)foo {
// [foo retain]; // 先保留新值
// [_foo release]; // 再释放旧值
// _foo = foo; // 更新实例变量,令其指向新值
[_foo release];
_foo = [foo retain];
}
顺序很重要。
假如还未保留新值就先把旧值释放了,而且两个值又指向同一个对象,那么,先执行的release操作就可能导致系统将此对象永久回收。而后续的retain操作则无法令这个已经彻底回收的对象复生,于是实例变量成了悬挂指针。
自动释放池:
autorelease,此方法会在稍后递减计数,通常是在下一次“事件循环”(event loop)时递减,不过也可能执行地更早些(自己创建的自动释放池)。
autorelease能延长对象生命期,使其在跨越方法调用边界后依然可以在存活一段时间。
一般用于方法中返回对象时。
例:
-(NSString *)stringValue {
NSString *str = [NSString alloc]initWithFormat:@"%@",self];
retrun [str autorelease];
}
保留环(retain cycle):
循环引用,无法释放
1、通常采用“弱引用”(weak reference,参见第33条)
2、或者从外界命令(nil)循环中的某个对象不再保留另外一个对象。
这两种方法都可以打破保留环,从而避免内存泄漏。