Cocoa內存管理主要是用引用計數,NSAutoreleasePool是用來支持引用計數的。
我們知道在一個對象被release的時候,意思就是已經釋放了這個對象,也不能再進行任何的調用。
如果我們不用到release,而是使用autorelease方法,那么這個對象就會進入NSAutoreleasePool,然后只有在pool被銷毀的時候,這個對象才真正的被銷毀。
舉個例子
- (void)viewDidLoad {
[super viewDidLoad];
//這是一個對象,封裝了autorelease方法
NSArray *arr = [NSArray arrayWithObject:@"舉個栗子"];
// Do any additional setup after loading the view, typically from a nib.
}
之前一直覺得是在出了作用域之后就被釋放了,但是看了一些資料,寫了點代碼實踐下。
上代碼:
//weak屬性的變量不會影響所指對象的生命周期
__weak id *obj_Weak = nil;
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *arr = [NSArray arrayWithObject:@"舉個栗子"];
obj_Weak = arr;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"viewWillAppear:%@", obj_Weak);
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"viewDidAppear:%@", obj_Weak);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
在每個方法中設置斷點,查看控制臺輸出:
當我們初始化數組的時候,當前對象的引用計數為1,并把對象自動添加到當前的autoreleasepool中。然后有其他局部變量指向這個對象時,對象的引用計數會+1,在viewDidLoad,我們用NSArray局部變量指向了對象,所以引用計數為2,而當viewDidLoad返回的時候,arr被釋放,因此對象引用計數-1,又變成了1。之后我們在viewWillAppear中可以看到還是能打印這個對象,這是因為這個對象是一個自動釋放的對象,所以它是被添加到當前的autoreleasepool中,只有這個autoreleasepool被drain的時候,autoreleasepool中的所有對象才會被釋放。最后對象在viewDidAppear中已經釋放了,這時候說明已經執行過drain了。
NSAutoreleasePool 釋放
NSAutoreleasePool的實例pool本身也是一個對象,同樣需要釋放,所以最后也同樣需要[pool release]或[pool drain],也正是這一行代碼,才會將池中的所有對象同時釋放。
NSAutoreleasePool的release最終調用的是AutoreleasePoolPage::pop(void *)來對pool中的對象執行釋放操作。
AutoreleasePoolPage
magic 用來校驗 AutoreleasePoolPage 的結構是否完整;
next 指向最新添加的 autoreleased 對象的下一個位置,初始化時指向 begin()
thread 指向當前線程;
parent 指向父結點,第一個結點的 parent 值為 nil
child 指向子結點,最后一個結點的 child 值為 nil
depth 代表深度,從 0 開始,往后遞增 1;
hiwat 代表 high water mark 。
NSThread、NSRunLoop 和 NSAutoreleasePool
根據蘋果官方文檔中對 NSRunLoop的描述,我們可以知道每一個線程,包括主線程,都會擁有一個專屬的 NSRunLoop 對象,并且會在有需要的時候自動創建。
同樣的,根據蘋果官方文檔中對 NSAutoreleasePool的描述,我們可知,在主線程的 NSRunLoop 對象(在系統級別的其他線程中應該也是如此,比如通過 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 獲取到的線程)的每個 event loop 開始前,系統會自動創建一個 autoreleasepool ,并在 event loop 結束時 drain 。
另外,NSAutoreleasePool 中還提到,每一個線程都會維護自己的 autoreleasepool 堆棧。換句話說 autoreleasepool 是與線程緊密相關的,每一個 autoreleasepool 只對應一個線程。
來自:http://blog.leichunfeng.com/blog/2015/05/31/objective-c-autorelease-pool-implementation-principle/