内存管理篇: 3.autorelease
autorelease的实质:
将创建的对象加入到NSAutoreleasePool管理“数组”中,并告知ARC系统暂时不要对此对象进行处理。待pool对象在其所属的NSRunLoop循环一次完成,准备释放(drain)时,对“数组”中的所有对象依次调用release方法。此时ARC再对对象进行内存管理。
GNUstep的实现
GNUstep的版本使用了同NSMutableArray一样的连接列表,将被标记的对象加入到“正在使用中的”autoreleasePool对象中。
// NSObject.m中:
- (id)autorelease {
[NSAutoreleasePool addObject:self];
}
// NSAutoreleasePool.m中:
+ (void)addObject:(id)anObj {
NSAutoreleasePool *pool = 获取正在使用中的pool;
if (pool != nil) {
[pool addObject:anObj];
} else {
...
}
}
- (void)addObject:(id)anObj {
// 加入到内部管理的数组中
[array addObject:anObj];
}
方法调用优化:在GNUstep实现的版本中,为了提高autorelease方法执行的速度,使用了“IMP Caching”的方式,及将函数指针提前缓存,需要时跳过了“objc_msgSend”的过程,直接调用:
// NSObject.m中:
// 缓存类名
id autorelease_class = [NSAutoreleasePool class];
// 缓存方法名
SEL autorelease_sel = @selector("addObject:");
// 缓存方法实现(函数指针)
IMP autorelease_imp = [autorelease_class methodForSelector:autorelease_sel];
- (id)autorelease {
// 直接调用
(*autorelease_imp)(autorelease_class, autorelease_sel, self);
}
注意:
由于NSAutoreleasePool覆盖了autorelease的方法实现(其他对象执行的是NSObject的实现),对pool对象发送autorelease消息会抛出异常。
即不能对NSAutoreleasePool对象调用autorelease方法。
- 补充:无论编译环境是否为ARC有效,都推荐使用@autoreleasepool块作为替代,以提高代码可读性。