NSAutoreleasePool是一个支持Cocoa引用计数的内存管理系统的对象。
1. 自动释放池
自动释放池(autorelease pool)会在消失时向池里的对象发送一条release消息。因此池里的对象会延迟释放直到自动释放池结束(如果这个对象还是retained,还是不会释放)。
应用(Application Kit)会在主线程的每个runloop循环开始时创建一个自动释放池,并且在循环结束时结束这个自动释放池。你一般不必创建自己的自动释放池,因为在main函数中已经创建。但是如果你在一个runloop中创建了很多autoreleased对象,你可以自己创建局部的自动释放池来降低内存峰值。
//ARC
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
}
return 0;
}
每一个线程(包括主线程)拥有它自己的NSAutoreleasePool栈。当一给新的pool创建时,它会被放到栈顶。当pools被结束时,它们会从栈中移除。而autoreleased的对象会被放在自动释放池中的顶部。当线程结束时,所有的自动释放池都会自动结束。
从前面可知,autoreleasePool是由NSRunLoop管理的。但是非主线程的NSRunLoop默认是不开启的,如果产生了autorelease对象,就会调用autoreleaseNoPage方法。它会自动帮你创建一个autoreleasePoolPage,然后push这个对象到autoreleasePoolPage栈中。
2. 内存管理
内存管理的规则:
- 自己生成的对象,自己持有。
- 非自己生成的对象,自己也能持有。
- 自己持有的对象不再需要时释放。
- 非自己持有的对象无法释放 。
__strong
修饰符表示对对象的强引用。持有强引用的变量在超出其作用域时被废弃,随着强引用的失效,引用的对象会随之释放。
作为alloc/new/copy/mutableCopy
方法的返回值而取得对象时,能够自己生成并持有对象。
//ARC有效
{
// 自己生成并持有对象
id __strong obj = [NSObject] alloc] init];
//因为obj为强引用,所以自己持有对象。
}
//因为obj变量超出其作用域,强引用失效。
//所以自动释放自己持有的对象。
//对象的所有者不存在,因此废弃该对象。
-------------------编译器模拟的代码---------------------
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_release(obj);
__autorelease
修饰符等价于ARC无效时调用对象的autorelease
方法。一般不用显式的调用。比如使用alloc/new/copy/mutableCopy
以外的方法创建对象时,编译器会自动将其返回值的对象注册到autoreleasepool。
@autoreleasepool {
//取得非自己生成并持有的对象
id __strong obj = [NSMutableArray array];
//因为变量obj为强引用,所有自己持有对象。
//并且该对象由编译器判断其方法名后自动注册到autoreleasepool。
}
//因为变量obj超出其作用域,强引用失效,所以自动释放自己所持有的对象。
//同时虽则@autoreleasepool块的结束,所有对象被自动释放。
//因为对象的所有者不存在,所以废弃其对象。
-------------------编译器模拟的代码---------------------
id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);
//objc_retainAutoreleasedReturnValue和objc_autoreleasedReturnValue是成对出现的。
__weak
修饰符表示对对象的弱引用,不持有对象实例。并且当该对象被废弃时,弱引用将自动失效且处于nil的状态(与__unsafe_unretained
不同)。
//ARC有效
{
//自己生成并持有对象
id __strong obj0 = [[NSObject alloc] init];
//因为obj0为强引用,所以自己持有对象。
id __weak obj1 = [[NSObject alloc] init];
//obj1变量持有生成对象的弱引用
}
//因为obj0变量超出其作用域,强引用失效。
//所以自动释放自己持有的对象.
//因为对象的所有者不存在,所以废弃其对象。
-------------------编译器模拟的代码---------------------
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
id obj1;
objc_initweak(&obj1, obj);
objc_release(obj);
objc_destroyWeak(&obj1);
参考
NSAutoreleasePool
Why __weak object will be added to autorelease pool?
引用计数带来的一次讨论
各个线程 Autorelease 对象的内存管理
does NSThread create autoreleasepool automaticly now?
Objective-C高级编程