- AutoReleasePool的實現原理?
- AutoReleasePool為什么可以嵌套調用?
自動釋放池
- 是以棧為節點通過雙向鏈表的形式結合而成的
- 是和線程一一對應的
通過clang編譯器查看@autoreleasepool{}
{
__AtAutoreleasePool __autoreleasepool;
...
}
__AtAutoreleasePool 又是什么?查看編譯后的結構
struct __AtAutoreleasePool {
//// 構造函數,在創建結構體的時候調用
__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
//// 析構函數,在結構體銷毀的時候調用
~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
void * atautoreleasepoolobj;
};
__AtAutoreleasePool是一個結構體,所以創建時會調用其構造函數__AtAutoreleasePool(),當離開其作用域后,會調用其析構函數~__AtAutoreleasePool()
查看objc源碼得到objc_autoreleasePoolPush和objc_autoreleasePoolPop的實現
void *
objc_autoreleasePoolPush(void)
{
return AutoreleasePoolPage::push();
}
void
objc_autoreleasePoolPop(void *ctxt)
{
AutoreleasePoolPage::pop(ctxt);
}
即相當于
objc_autoreleasePoolPush(void)
....{}中的代碼
objc_autoreleasePoolPop(void *ctxt)
那么其實可以看出自動釋放池是由AutoreleasePoolPage實現的
通過objc源碼查看其數據結構,它是一個c++的class
class AutoreleasePoolPage {
....
magic_t const magic; //用來校驗 AutoreleasePoolPage 的結構是否完整
id *next;//指向最新添加的 autoreleased 對象的下一個位置,初始化時指向 begin()
pthread_t const thread;//指向當前線程
AutoreleasePoolPage * const parent;//指向父結點,第一個結點的 parent 值為 nil
AutoreleasePoolPage *child;//指向子結點,最后一個結點的 child 值為 nil
uint32_t const depth;//代表深度,從 0 開始,往后遞增 1
uint32_t hiwat;//代表 high water mark
...
}
每個AutoreleasePoolPage對象占用4096字節內存,除了用來存放它內部的成員變量,剩下的空間用來存放autorelease對象的地址
所有的AutoreleasePoolPage對象通過雙向鏈表的形式連接在一起
一次pop相當于一次批量的pop操作