最近和 bestswifter 、kuailejim 搞了一套模擬面試,然后不管是應(yīng)屆生還是工作兩三年的高級工程師都對下面這幾個問題比較懵逼肝断,可能是開發(fā)中用到的不多,在這里淺淺的討論下
- Autoreleasepool 與 Runloop 的關(guān)系
- ARC 下什么樣的對象由 Autoreleasepool 管理
- 子線程默認(rèn)不會開啟 Runloop,那出現(xiàn) Autorelease 對象如何處理胸懈?不手動處理會內(nèi)存泄漏嗎担扑?
針對第一個問題,比較容易理解趣钱,可以看一下:ibireme 的 深入理解RunLoop涌献,主線程默認(rèn)為我們開啟 Runloop,Runloop 會自動幫我們創(chuàng)建Autoreleasepool首有,并進行Push燕垃、Pop 等操作來進行內(nèi)存管理
第二個問題,ARC 下什么樣的對象由 Autoreleasepool 管理呢井联?大多數(shù)人的回答是:“都會由 pool 進行管理”卜壕。其實并不是這樣的,對于普通的對象是由編譯器在合適的地方為我們 Realease 了烙常。針對這個問題轴捎,我已經(jīng)總結(jié)過:引用計數(shù)帶來的一次討論,是參考了經(jīng)典的《iOS與OS X多線程和內(nèi)存管理 》這本書蚕脏。
針對第三個問題侦副,感覺比較難以回答,需要很細(xì)致的讀過 Runtime 驼鞭、Autoreleasepool 的源碼才可以秦驯。我也是參考了 StackOverFlow 的回答:does NSThread create autoreleasepool automaticly now?。我再來簡單闡述下终议,在子線程你創(chuàng)建了 Pool 的話汇竭,產(chǎn)生的 Autorelease 對象就會交給 pool 去管理。如果你沒有創(chuàng)建 Pool 穴张,但是產(chǎn)生了 Autorelease 對象细燎,就會調(diào)用 autoreleaseNoPage 方法。在這個方法中皂甘,會自動幫你創(chuàng)建一個 hotpage(hotPage 可以理解為當(dāng)前正在使用的 AutoreleasePoolPage玻驻,如果你還是不理解,可以先看看 Autoreleasepool 的源代碼偿枕,再來看這個問題 )璧瞬,并調(diào)用 page->add(obj)
將對象添加到 AutoreleasePoolPage 的棧中,也就是說你不進行手動的內(nèi)存管理渐夸,也不會內(nèi)存泄漏啦嗤锉!StackOverFlow 的作者也說道,這個是 OS X 10.9+和 iOS 7+ 才加入的特性墓塌。并且蘋果沒有對應(yīng)的官方文檔闡述此事瘟忱,但是你可以通過源碼了解奥额。這里張貼部分源代碼:
static __attribute__((noinline))
id *autoreleaseNoPage(id obj)
{
// No pool in place.
// hotPage 可以理解為當(dāng)前正在使用的 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 可以理解為當(dāng)前正在使用的 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);
}