void *objc_autoreleasePoolPush(void)
{
return AutoreleasePoolPage::push();
}
void objc_autoreleasePoolPop(void *ctxt)
{
AutoreleasePoolPage::pop(ctxt);
}
複製代碼
上面的方法看上去是對 AutoreleasePoolPage 對應靜態方法 push
和 pop
的封裝。bash
class AutoreleasePoolPage
{
magic_t const magic;//完整性的校驗
id *next;//保存了當前頁所在的線程
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
}
複製代碼
每個自動釋放池都是由一系列的 AutoreleasePoolPage 組成的,而且每個 AutoreleasePoolPage 的大小都是 4096 字節(16 進制 0x1000)函數
自動釋放池中的 AutoreleasePoolPage
是以雙向鏈表的形式鏈接起來的:ui
POOL_BOUNDARY
只是nil的別名spa
#define POOL_BOUNDARY nil
複製代碼
在每一個自動釋放池初始化調用 objc_autoreleasePoolPush 的時候,都會把一個 POOL_SENTINEL push 到自動釋放池的棧頂,而且返回這個 POOL_BOUNDARY 哨兵對象。線程
int main(int argc, const char * argv[]) {
{
void * atautoreleasepoolobj = objc_autoreleasePoolPush();
// do whatever you want
objc_autoreleasePoolPop(atautoreleasepoolobj);
}
return 0;
}
複製代碼
上面的 atautoreleasepoolobj 就是一個 POOL_BOUNDARY。指針
而當方法 objc_autoreleasePoolPop 調用時,就會向自動釋放池中的對象發送 release 消息,直到第一個 POOL_BOUNDARY:code
瞭解了 POOL_BOUNDARY,咱們來從新回顧一下 objc_autoreleasePoolPush 方法:cdn
static inline void *push()
{
id *dest;
if (DebugPoolAllocation) {
// Each autorelease pool starts on a new pool page.
dest = autoreleaseNewPage(POOL_BOUNDARY);
} else {
dest = autoreleaseFast(POOL_BOUNDARY);
}
assert(dest == EMPTY_POOL_PLACEHOLDER || *dest == POOL_BOUNDARY);
return dest;
}
複製代碼
在這裏會進入一個比較關鍵的方法 autoreleaseFast,並傳入哨兵對象 POOL_SENTINEL:對象
static inline id *autoreleaseFast(id obj)
{
AutoreleasePoolPage *page = hotPage();
if (page && !page->full()) {
return page->add(obj);
} else if (page) {
return autoreleaseFullPage(obj, page);
} else {
return autoreleaseNoPage(obj);
}
}
複製代碼
上述方法分三種狀況選擇不一樣的代碼執行:blog
hotPage
而且當前 page
不滿
hotPage
而且當前 page
已滿