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

最近和 bestswifterkuailejim 搞了一套模擬面試,而後無論是應屆生仍是工做兩三年的高級工程師都對下面這幾個問題比較懵逼,多是開發中用到的很少,在這裏淺淺的討論下面試

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

針對第一個問題,比較容易理解,能夠看一下:ibireme深刻理解RunLoop,主線程默認爲咱們開啓 Runloop,Runloop 會自動幫咱們建立Autoreleasepool,並進行Push、Pop 等操做來進行內存管理swift

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

針對第三個問題,感受比較難以回答,須要很細緻的讀過 Runtime 、Autoreleasepool 的源碼才能夠。我也是參考了 StackOverFlow 的回答:does NSThread create autoreleasepool automaticly now?。我再來簡單闡述下,在子線程你建立了 Pool 的話,產生的 Autorelease 對象就會交給 pool 去管理。若是你沒有建立 Pool ,可是產生了 Autorelease 對象,就會調用 autoreleaseNoPage 方法。在這個方法中,會自動幫你建立一個 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.
    // 幫你建立一個 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

相關文章
相關標籤/搜索