各個線程 Autorelease 對象的內存管理

最近和 bestswifter 、kuailejim 搞了一套模擬面試,然后不管是應屆生還是工作兩三年的高級工程師都對下面這幾個問題比較懵逼,可能是開發(fā)中用到的不多,在這里淺淺的討論下

  • Autoreleasepool 與 Runloop 的關系
  • ARC 下什么樣的對象由 Autoreleasepool 管理
  • 子線程默認不會開啟 Runloop,那出現 Autorelease 對象如何處理?不手動處理會內存泄漏嗎?

針對第一個問題,比較容易理解,可以看一下:ibireme深入理解RunLoop,主線程默認為我們開啟 Runloop,Runloop 會自動幫我們創(chuàng)建Autoreleasepool,并進行Push、Pop 等操作來進行內存管理

第二個問題,ARC 下什么樣的對象由 Autoreleasepool 管理呢?大多數人的回答是:“都會由 pool 進行管理”。其實并不是這樣的,對于普通的對象是由編譯器在合適的地方為我們 Realease 了。針對這個問題,我已經總結過:引用計數帶來的一次討論,是參考了經典的《iOS與OS X多線程和內存管理 》這本書。

針對第三個問題,感覺比較難以回答,需要很細致的讀過 Runtime 、Autoreleasepool 的源碼才可以。我也是參考了 StackOverFlow 的回答:does NSThread create autoreleasepool automaticly now?。我再來簡單闡述下,在子線程你創(chuàng)建了 Pool 的話,產生的 Autorelease 對象就會交給 pool 去管理。如果你沒有創(chuàng)建 Pool ,但是產生了 Autorelease 對象,就會調用 autoreleaseNoPage 方法。在這個方法中,會自動幫你創(chuàng)建一個 hotpage(hotPage 可以理解為當前正在使用的 AutoreleasePoolPage,如果你還是不理解,可以先看看 Autoreleasepool 的源代碼,再來看這個問題 ),并調用 page->add(obj)將對象添加到 AutoreleasePoolPage 的棧中,也就是說你不進行手動的內存管理,也不會內存泄漏啦!StackOverFlow 的作者也說道,這個是 OS X 10.9+和 iOS 7+ 才加入的特性。并且蘋果沒有對應的官方文檔闡述此事,但是你可以通過源碼了解。這里張貼部分源代碼:

static __attribute__((noinline))
id *autoreleaseNoPage(id obj)
{
    // No pool in place.
    // hotPage 可以理解為當前正在使用的 AutoreleasePoolPage。
    assert(!hotPage());
    
    // POOL_SENTINEL 只是 nil 的別名
    if (obj != POOL_SENTINEL  &&  DebugMissingPools) {
        // We are pushing an object with no pool in place, 
        // and no-pool debugging was requested by environment.
        _objc_inform("MISSING POOLS: Object %p of class %s "
                     "autoreleased with no pool in place - "
                     "just leaking - break on "
                     "objc_autoreleaseNoPool() to debug", 
                     (void*)obj, object_getClassName(obj));
        objc_autoreleaseNoPool(obj);
        return nil;
    }
    
    // Install the first page.
    // 幫你創(chuàng)建一個 hotpage(hotPage 可以理解為當前正在使用的 AutoreleasePoolPage
    AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);
    setHotPage(page);

    // Push an autorelease pool boundary if it wasn't already requested.
    // POOL_SENTINEL 只是 nil 的別名,哨兵對象
    if (obj != POOL_SENTINEL) {
        page->add(POOL_SENTINEL);
    }

    // Push the requested object.
    // 把對象添加到 自動釋放池 進行管理
    return page->add(obj);
}

Reference

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容