自動釋放池-AutoReleasePool

自動釋放池-AutoReleasePool

自動釋放池是OC中的一種內(nèi)存自動回收機(jī)制莉炉,它可以將加入AutoreleasePool中的變量release的時機(jī)延遲,簡單來說梆暮,就是當(dāng)創(chuàng)建一個對象绍昂,在正常情況下啦粹,變量會在超出其作用域的時立即release窘游。如果將對象加入到了自動釋放池中,這個對象并不會立即釋放贪嫂,會等到runloop休眠/超出autoreleasepool作用域{}之后才會被釋放


image.jpeg

1艾蓝、從程序啟動到加載完成,主線程對應(yīng)的runloop會處于休眠狀態(tài)赢织,等待用戶交互來喚醒runloop
2、用戶的每一次交互都會啟動一次runloop于置,用于處理用戶的所有點擊、觸摸事件等
3饱狂、runloop在監(jiān)聽到交互事件后宪彩,就會創(chuàng)建自動釋放池,并將所有延遲釋放的對象添加到自動釋放池中
4尿孔、在一次完整的runloop結(jié)束之前,會向自動釋放池中所有對象發(fā)送release消息活合,然后銷毀自動釋放池
總結(jié)

  • autoreleasepool其本質(zhì)是一個結(jié)構(gòu)體對象,一個自動釋放池對象就是頁留晚,是是棧結(jié)構(gòu)存儲告嘲,符合先進(jìn)后出的原則即可

  • 頁的棧底是一個56字節(jié)大小的空占位符,一頁總大小為4096字節(jié)

  • 只有第一頁有哨兵對象橄唬,最多存儲504個對象,從第二頁開始最多存儲505個對象

  • autoreleasepool在加入要釋放的對象時隆判,底層調(diào)用的是objc_autoreleasePoolPush方法

  • autoreleasepool在調(diào)用析構(gòu)函數(shù)釋放時僧界,內(nèi)部的實現(xiàn)是調(diào)用objc_autoreleasePoolPop方法
    image.jpeg

對于自動釋放池,我們主要關(guān)心的點有以下三點:
1捂襟、自動釋放池什么時候創(chuàng)建?
2郎汪、對象是如何加入自動釋放池的闯狱?
3、哪些對象才會加入自動釋放池哄孤?

image.jpeg


objc_autoreleasePoolPush 源碼分析

  • 判斷是否為有 pool

  • 如果沒有,則通過autoreleaseNewPage方法創(chuàng)建

  • 如果有凝危,則通過autoreleaseFast壓棧哨兵對象
    image.jpeg

1、創(chuàng)建頁 autoreleaseNewPage

  • 進(jìn)入objc_autoreleasePoolPush -> push -> autoreleaseNewPage源碼實現(xiàn)蛾默,主要是通過hotPage`獲取當(dāng)前頁,判斷當(dāng)前頁是否存在

  • 如果存在冬念,則通過autoreleaseFullPage方法壓棧對象

  • 如果不存在,則通過autoreleaseNoPage方法創(chuàng)建頁
    image.jpeg

    image.jpeg

    image.jpeg

    其中autoreleaseNoPage方法中發(fā)現(xiàn)當(dāng)前線程的自動釋放池是通過AutoreleasePoolPage創(chuàng)建的,其定義中有構(gòu)造方法瀑构,而構(gòu)造方法的實現(xiàn)是通過父類AutoreleasePoolPageData的初始化方法
    image.jpeg

2、壓棧對象 autoreleaseFast

  • 進(jìn)入autoreleaseFast源碼据块,主要有以下幾步:

  • 獲取當(dāng)前操作頁折剃,并判斷頁是否存在以及是否滿了

  • 如果頁存在,且未滿怕犁,則通過add方法壓棧對象

  • 如果頁存在,且滿了戈轿,則通過autoreleaseFullPage方法安排新的頁面

  • 如果頁不存在阵子,則通過autoreleaseNoPage方法創(chuàng)建新頁
    image.jpeg

    image.jpeg

    add 方法
    image.jpeg

    3挠进、autorelease 底層分析
    如果不是對象 或者 是小對象色乾,則直接返回

    如果是對象领突,則調(diào)用對象的autorelease進(jìn)行釋放
    image.jpeg

objc_autoreleasePoolPop 源碼分析
進(jìn)入pop源碼實現(xiàn)君旦,主要由以下幾步

  • 空頁面的處理嘲碱,并根據(jù)token獲取page

  • 容錯處理

  • 通過popPage出棧頁

  • image.jpeg

    image.jpeg

image.jpeg

  • 進(jìn)入releaseUntil實現(xiàn)局蚀,主要是通過循環(huán)遍歷,判斷對象是否等于stop琅绅,其目的是釋放stop之前的所有的對象,

  • 首先通過獲取page的next釋放對象(即page的最后一個對象)宵蛀,并對next進(jìn)行遞減县貌,獲取上一個對象

  • 判斷是否是哨兵對象凑懂,如果不是則自動調(diào)用objc_release釋放
    image.jpeg

    image.jpeg

    進(jìn)入kill實現(xiàn),主要是銷毀當(dāng)前頁接谨,將當(dāng)前頁賦值為父節(jié)點頁齐媒,并將父節(jié)點頁的child對象指針置為nil

    image.jpeg

總結(jié)

  • 在自動釋放池的壓棧(即push)操作中

  • 當(dāng)沒有pool,即只有空占位符(存儲在tls中)時扫夜,則創(chuàng)建頁,壓棧哨兵對象

  • 在頁中壓棧普通對象主要是通過next指針遞增進(jìn)行的笤闯,

  • 當(dāng)頁滿了時,需要設(shè)置頁的child對象為新建頁
    image.jpeg

  • 在自動釋放池的出棧(即pop)操作中

  • 在頁中出棧普通對象主要是通過next指針遞減進(jìn)行的超陆,

  • 當(dāng)頁空了時浦马,需要賦值頁的parent對象為當(dāng)前頁
    image.jpeg

相關(guān)面試題

AutoreleasePool 相關(guān)
面試題1:臨時變量什么時候釋放?

  • 如果在正常情況下退唠,一般是超出其作用域就會立即釋放
  • 如果將臨時變量加入了自動釋放池荤胁,會延遲釋放瞧预,即在runloop休眠或者autoreleasepool作用域之后釋放 面試題2:AutoreleasePool原理
  • 自動釋放池的本質(zhì)是一個AutoreleasePoolPage結(jié)構(gòu)體對象,是一個棧結(jié)構(gòu)存儲的頁盆驹,每一個AutoreleasePoolPage都是以雙向鏈表的形式連接
  • 自動釋放池的壓棧和出棧主要是通過結(jié)構(gòu)體的構(gòu)造函數(shù)和析構(gòu)函數(shù)調(diào)用底層的objc_autoreleasePoolPush和objc_autoreleasePoolPop滩愁,實際上是調(diào)用AutoreleasePoolPage的push和pop兩個方法
  • 每次調(diào)用push操作其實就是創(chuàng)建一個新的AutoreleasePoolPage,而AutoreleasePoolPage的具體操作就是插入一個POOL_BOUNDARY硝枉,并返回插入POOL_BOUNDARY的內(nèi)存地址。而push內(nèi)部調(diào)用autoreleaseFast方法處理妻味,主要有以下三種情況
  • 當(dāng)page存在,且不滿時焦履,調(diào)用add方法將對象添加至page的next指針處,并next遞增
  • 當(dāng)page存在嘉裤,且已滿時栖博,調(diào)用autoreleaseFullPage初始化一個新的page,然后調(diào)用add方法將對象添加至page棧中
  • 當(dāng)page不存在時仇让,調(diào)用autoreleaseNoPage創(chuàng)建一個hotPage,然后調(diào)用add方法將對象添加至page棧中
  • 當(dāng)執(zhí)行pop操作時妹孙,會傳入一個值,這個值就是push操作的返回值骇笔,即POOL_BOUNDARY的內(nèi)存地址token嚣崭。所以pop內(nèi)部的實現(xiàn)就是根據(jù)token找到哨兵對象所處的page中笨触,然后使用 objc_release 釋放 token之前的對象雹舀,并把next 指針到正確位置 面試題3:AutoreleasePool能否嵌套使用?
  • 可以嵌套使用说榆,其目的是可以控制應(yīng)用程序的內(nèi)存峰值寸认,使其不要太高
  • 可以嵌套的原因是因為自動釋放池是以棧為節(jié)點串慰,通過雙向鏈表的形式連接的,且是和線程一一對應(yīng)的
  • 自動釋放池的多層嵌套其實就是不停的pushs哨兵對象邦鲫,在pop時,會先釋放里面的古今,在釋放外面的 面試題4:哪些對象可以加入AutoreleasePool滔以?alloc創(chuàng)建可以嗎捉腥?
  • 使用new醉者、alloc披诗、copy關(guān)鍵字生成的對象和retain了的對象需要手動釋放,不會被添加到自動釋放池中
  • 設(shè)置為autorelease的對象不需要手動釋放剥槐,會直接進(jìn)入自動釋放池
  • 所有 autorelease 的對象,在出了作用域之后粒竖,會被自動添加到最近創(chuàng)建的自動釋放池中 面試題5:AutoreleasePool的釋放時機(jī)是什么時候几于?
  • App 啟動后蕊苗,蘋果在主線程 RunLoop 里注冊了兩個 Observer,其回調(diào)都是_wrapRunLoopWithAutoreleasePoolHandler()沿彭。
  • 第一個 Observer 監(jiān)視的事件是 Entry(即將進(jìn)入 Loop)朽砰,其回調(diào)內(nèi)會調(diào)用 _objc_autoreleasePoolPush() 創(chuàng)建自動釋放池。其 order 是 -2147483647喉刘,優(yōu)先級最高瞧柔,保證創(chuàng) 建釋放池發(fā)生在其他所有回調(diào)之前。
  • 第二個 Observer 監(jiān)視了兩個事件: BeforeWaiting(準(zhǔn)備進(jìn)入休眠) 時調(diào)用 _objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 釋放舊的池并創(chuàng)建新池;Exit(即 將退出 Loop) 時調(diào)用 _objc_autoreleasePoolPop() 來釋放自動釋放池睦裳。這個 Observer 的 order 是 2147483647造锅,優(yōu)先級最低,保證其釋放池子發(fā)生在其他所有回調(diào)之后廉邑。 面試題6:thread 和 AutoreleasePool的關(guān)系
  • 每個線程哥蔚,包括主線程在內(nèi)都維護(hù)了自己的自動釋放池堆棧結(jié)構(gòu)
  • 新的自動釋放池在被創(chuàng)建時倒谷,會被添加到棧頂;當(dāng)自動釋放池銷毀時糙箍,會從棧中移除
  • 對于當(dāng)前線程來說,會將自動釋放的對象放入自動釋放池的棧頂倍靡;在線程停止時猴伶,會自動釋放掉與該線程關(guān)聯(lián)的所有自動釋放池
    總結(jié):每個線程都有與之關(guān)聯(lián)的自動釋放池堆棧結(jié)構(gòu),新的pool在創(chuàng)建時會被壓棧到棧頂塌西,pool銷毀時他挎,會被出棧,對于當(dāng)前線程來說捡需,釋放對象會被壓棧到棧頂办桨,線程停止時,會自動釋放與之關(guān)聯(lián)的自動釋放池 面試題7:RunLoop 和 AutoreleasePool的關(guān)系
  • 主程序的RunLoop在每次事件循環(huán)之前之前站辉,會自動創(chuàng)建一個 autoreleasePool
  • 并且會在事件循環(huán)結(jié)束時呢撞,執(zhí)行drain操作,釋放其中的對象
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饰剥,一起剝皮案震驚了整個濱河市殊霞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌汰蓉,老刑警劉巖绷蹲,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異顾孽,居然都是意外死亡祝钢,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進(jìn)店門若厚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拦英,“玉大人,你說我怎么就攤上這事测秸“坦溃” “怎么了?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵乞封,是天一觀的道長做裙。 經(jīng)常有香客問我,道長肃晚,這世上最難降的妖魔是什么锚贱? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮关串,結(jié)果婚禮上拧廊,老公的妹妹穿的比我還像新娘监徘。我一直安慰自己,他們只是感情好吧碾,可當(dāng)我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布凰盔。 她就那樣靜靜地躺著,像睡著了一般倦春。 火紅的嫁衣襯著肌膚如雪户敬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天睁本,我揣著相機(jī)與錄音尿庐,去河邊找鬼。 笑死呢堰,一個胖子當(dāng)著我的面吹牛抄瑟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播枉疼,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼皮假,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了骂维?” 一聲冷哼從身側(cè)響起惹资,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎席舍,沒想到半個月后布轿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哮笆,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡来颤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了稠肘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片福铅。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖项阴,靈堂內(nèi)的尸體忽然破棺而出滑黔,到底是詐尸還是另有隱情,我是刑警寧澤环揽,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布略荡,位于F島的核電站,受9級特大地震影響歉胶,放射性物質(zhì)發(fā)生泄漏汛兜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一通今、第九天 我趴在偏房一處隱蔽的房頂上張望粥谬。 院中可真熱鬧肛根,春花似錦、人聲如沸漏策。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掺喻。三九已至芭届,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間感耙,已是汗流浹背喉脖。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留抑月,地道東北人树叽。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像谦絮,于是被迫代替她去往敵國和親题诵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內(nèi)容