AutoreleasePool

AutoReleasePool

AutoreleasePool的實現原理

@autoreleasePool = __AtAutoreleasePool __autoreleasePoolc++

__AtAutoreleasePool 結構體
複製代碼

AutoreleasePool 是 oc 的一種內存回收機制,正常狀況下變量在超出做用域的時候 release,可是若是將變量加入到 pool 中,那麼release 將延遲執行objective-c

AutoreleasePool 並無單獨的結構,而是由若干個 AutoreleasePoolPage 以**雙向鏈表**形式組成

1. PAGE_MAX_SIZE :4KB,虛擬內存每一個扇區的大小,內存對齊
2. 內部 thread ,page 當前所在的線程,AutoreleasePool是按線程一一對應的
3. 自己的成員變量佔用56字節,剩下的內存存儲了調用 autorelease 的變量的對象的地址,同時將一個哨兵插入page中
4. pool_boundry 哨兵標記,哨兵其實就是一個空地址,用來區分每個page 的邊界
5. 當一個Page被佔滿後,會新建一個page,並插入哨兵標記
複製代碼

單個自動釋放池的執行過程就是objc_autoreleasePoolPush() —> [object autorelease] —> objc_autoreleasePoolPop(void *)markdown

具體實現以下:oop

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

void objc_autoreleasePoolPop(void *ctxt) {
    AutoreleasePoolPage::pop(ctxt);
}
複製代碼

內部其實是對 AutoreleasePoolPage 的調用ui

objc_autoreleasePoolPush

每當自動釋放池調用 objc_autoreleasePoolPush 時,都會把邊界對象放進棧頂,而後返回邊界對象,用於釋放。spa

AutoreleasePoolPage::push(); 調用👇線程

static inline void *push() {
   return autoreleaseFast(POOL_BOUNDARY);
}
複製代碼

autoreleaseFast👇指針

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);
   }
}
複製代碼

👆上述方法分三種狀況選擇不一樣的代碼執行:code

- 有 hotPage 而且當前 page 不滿,調用 page->add(obj) 方法將對象添加至 AutoreleasePoolPage 的棧中
- 有 hotPage 而且當前 page 已滿,調用 autoreleaseFullPage 初始化一個新的頁,調用 page->add(obj) 方法將對象添加至 AutoreleasePoolPage 的棧中
- 無 hotPage,調用 autoreleaseNoPage 建立一個 hotPage,調用 page->add(obj) 方法將對象添加至 AutoreleasePoolPage 的棧中

最後的都會調用 page->add(obj) 將對象添加到自動釋放池中。 hotPage 能夠理解爲當前正在使用的 AutoreleasePoolPage。
複製代碼

AutoreleasePoolPage

是以棧的形式存在,而且內部對象經過進棧、出棧對應着 objc_autoreleasePoolPush 和 objc_autoreleasePoolPop
  
當咱們對一個對象發送一條 autorelease 消息時,其實是將這個對象地址加入到 autoreleasePoolPage 的棧頂 next 指針的指向的位置
複製代碼

Runloop 與 Autorelease

iOS 在主線程註冊了兩個 observerorm

__第一個observer __

監聽了 kCFRunloopEntry, 會調用 objc_autoreleasePool_push()

第二個 observer

監聽了 kCFRunloopBeforeWaiting 會調用 objc_autoreleasePool_pop() 、objc_autoreleasePool_push()

監聽了 kCFRunloopExit 事件,會調用 objc_autoreleasePool_pop()

相關文章
相關標籤/搜索