AutoreleasePool的實現

AutoreleasePool的基本函數

void *objc_autoreleasePoolPush(void)
{
    return AutoreleasePoolPage::push();
}

void objc_autoreleasePoolPop(void *ctxt)
{
    AutoreleasePoolPage::pop(ctxt);
}

複製代碼

上面的方法看上去是對 AutoreleasePoolPage 對應靜態方法 pushpop 的封裝。bash

AutoreleasePoolPage

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

parent 和 child 就是用來構造雙向鏈表的指針。

POOL_BOUNDARY (哨兵對象)

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

objc_autoreleasePoolPush 方法

瞭解了 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 不滿
    • 調用 page->add(obj) 方法將對象添加至 AutoreleasePoolPage 的棧中
  • hotPage 而且當前 page 已滿
相關文章
相關標籤/搜索