AutoreleasePool 是一個抽象概念阱驾,并沒有實際結(jié)構(gòu)就谜,真實的結(jié)構(gòu)是一個雙向鏈表『AutoreleasePoolPage』,由C++實現(xiàn)里覆。
1.數(shù)據(jù)結(jié)構(gòu)
其數(shù)據(jù)結(jié)構(gòu)如下:
class AutoreleasePoolPage
{
#define POOL_SENTINEL nil
static pthread_key_t const key = AUTORELEASE_POOL_KEY;
static uint8_t const SCRIBBLE = 0xA3; // 0xA3A3A3A3 after releasing
static size_t const SIZE =
#if PROTECT_AUTORELEASEPOOL
PAGE_MAX_SIZE; // must be multiple of vm page size
#else
PAGE_MAX_SIZE; // size and alignment, power of 2
#endif
static size_t const COUNT = SIZE / sizeof(id);
magic_t const magic;
id *next;
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
}
成員變量說明:
next
:游標丧荐,一直指向最新入棧的autorelease對象的下一個位置。
key
:TLS技術(shù)喧枷,既Thread Local Storage(TLS)線程局部存儲虹统。目的很簡單,將一塊內(nèi)存作為某個線程專有的存儲割去,以key-value的形式進行讀寫窟却。AutoreleasePoolPage將這塊區(qū)域用作存儲最新的Page,既hotPage呻逆。
SIZE
:單個page的最大存儲數(shù)量,AutoreleasePoolPage以雙向鏈表的形式存在菩帝,但是單個page的存儲是有限額的咖城,(id *) ((uint8_t *)this+SIZE)
。
thread
:當前線程pthread_self()
呼奢。
2.push和pop
當我們手動調(diào)用@autoreleasePool的時候宜雀,編譯器會自動將大括號內(nèi)的所有對象標記為autorelease前綴。AutoreleasePoolPage::autorelease((id)this)
當前對象本身作為參數(shù)入?yún)⑽沾。贿^在討論對象的autorelease之前辐董,編譯器還插入了兩個方法:
void *pool = objc_autoreleasePoolPush();
……
……
……
objc_autoreleasePoolPop(pool);
前者做了和對象的autorelease相同的事情:
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);
}
}
id *add(id obj)
{
assert(!full());
unprotect();
id *ret = next; // faster than `return next-1` because of aliasing
*next++ = obj;
protect();
return ret;
}
主要就是移動游標,并且返回當前位置禀综,這個返回參數(shù)的意義主要體現(xiàn)在
objc_autoreleasePoolPop(pool);
的入?yún)⒅屑蚝妫琾ool記錄著一個pool的初始位置,根據(jù)這個位置和當前的hotPage位置定枷,遍歷中間所有的對象孤澎,進行釋放。并且由于雙向鏈表的結(jié)構(gòu)欠窒,很容易跨page進行遍歷覆旭。