關(guān)于對(duì)iOS中自動(dòng)釋放池autoreleasepool的一些理解

因?yàn)楝F(xiàn)在大家都在使用ARC模式下進(jìn)行編程,一個(gè)很重要的問題也是最容易被大家所忽視的問題就是自動(dòng)釋放池,大部分程序員尤其是剛?cè)胄械亩贾皇侵烙羞@么一個(gè)東西,但具體是什么,工作的原理是什么,在什么時(shí)候使用它都一概不知。所以寫一篇文章,記錄一下個(gè)人對(duì)自動(dòng)釋放池的一些理解。

我們新建一個(gè)OC項(xiàng)目,在main函數(shù)中可以看到這么一串代碼:

int main(int argc, char * argv[]) {

@autoreleasepool {

return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

}

}

其中就引用了一個(gè)自動(dòng)釋放池。其實(shí),自動(dòng)釋放池@autoreleasepool{}在系統(tǒng)中所編譯的代碼為:

1.void *ctx = objc_autoreleasepoolPush(); ? ? //創(chuàng)建一個(gè)無類型指針的哨兵對(duì)象

2.執(zhí)行@autoreleasepool{}中對(duì)應(yīng){}里所書寫的代碼

3.執(zhí)行objc_autoreleasepool(ctx);//釋放哨兵對(duì)象所分隔區(qū)域內(nèi)所有對(duì)象的引用計(jì)數(shù)

由以上可以看出,autoreleasepool工作的原理就是一個(gè)壓棧,一個(gè)出棧,push方法創(chuàng)建哨兵對(duì)象作為標(biāo)記,pop操作作批量引用計(jì)數(shù)釋放的工作。

介紹完大概代碼的原理之后說一下一個(gè)比較官方的對(duì)于autoreleasePool的總結(jié)吧。

autoreleasepool是以棧為節(jié)點(diǎn),通過雙向鏈表的形式組合而成的,autoreleasepool是與線程一一對(duì)應(yīng)的。

那么什么是雙向鏈表呢,雙向鏈表的單位是節(jié)點(diǎn),從頭結(jié)點(diǎn)開始一直到尾節(jié)點(diǎn),每一個(gè)節(jié)點(diǎn)都會(huì)有一個(gè)父指針和子指針,父指針指向前一個(gè)節(jié)點(diǎn),子指針指向后一個(gè)節(jié)點(diǎn),而頭節(jié)點(diǎn)的父指針指向NULL,尾節(jié)點(diǎn)的子指針指向NULL。這樣就把??臻g通過雙向鏈表的形式連接起來了。

而autoreleasepoolPage就是雙鏈鏈表中每一個(gè)節(jié)點(diǎn)的長(zhǎng)度了,可以說,autoreleasepoolPage把??臻g中一些大小的空間分割成一個(gè)個(gè)單位,稱為節(jié)點(diǎn),然后通過雙向鏈表的形式連接起來,這就成了一個(gè)整體的autoreleasepool的結(jié)構(gòu)了。

在AutoreleasePool中有四個(gè)變量分別是:1.id *next一個(gè)id類型的指針,指向的是下一個(gè)可存儲(chǔ)對(duì)象的位置,2.AutoreleasepoolPage* const parent;這就是當(dāng)前page父節(jié)點(diǎn)page的地址指針。3.AutoreleasepoolPage* child,同理,是子節(jié)點(diǎn)表地址的指針。4.pthread_t const thread;這個(gè)變量中就記錄了線程的情況,所以說自動(dòng)釋放池是與線程一一對(duì)應(yīng)的關(guān)系。

在介紹了自動(dòng)釋放池整體結(jié)構(gòu)之后,接下來就說自動(dòng)釋放池關(guān)大象的三個(gè)步驟:

一、把冰箱門打開

調(diào)用objc_autoreleasepoolPush()方法,在當(dāng)前autoreleasepoolPage中的next指針位置創(chuàng)建一個(gè)為nil的哨兵對(duì)象,隨后將next指針的位置指向下一個(gè)內(nèi)存地址。

二、把大象關(guān)進(jìn)去

第二步就是執(zhí)行代碼了,在自動(dòng)釋放池范圍內(nèi)的代碼被執(zhí)行,給逐個(gè)對(duì)象調(diào)用[object autorelease]方法。其實(shí)在autorelease方法內(nèi)部實(shí)現(xiàn)的步驟為:1.判斷next指針是否已經(jīng)在棧頂了,如果是,則增加一個(gè)棧節(jié)點(diǎn)到鏈表上,隨后增加一個(gè)對(duì)象到新的棧節(jié)點(diǎn)鏈表中,如果不是的話則在next指針?biāo)傅奈恢锰砑右粋€(gè)調(diào)用autorelease方法的對(duì)象。

三、把冰箱門關(guān)上(其實(shí)是把大象取出來)

第三部就是執(zhí)行objc_autoreleasepoolPop()方法,該方法會(huì)根據(jù)傳入的哨兵對(duì)象找到對(duì)應(yīng)的內(nèi)存位置,然后根據(jù)哨兵對(duì)象的位置給上次push后添加的對(duì)象依次發(fā)送release消息,然后回退next指針到正確的位置。

以上三個(gè)步驟就是在autorelease自動(dòng)釋放池中進(jìn)行的操作,也是這三個(gè)步驟構(gòu)成了自動(dòng)釋放池。

所以總結(jié)一下,main函數(shù)中的autoreleasepool是在runloop結(jié)束的時(shí)候調(diào)用objc_autoreleasepoolPop的方法的,多層嵌套的autoreleasepool其實(shí)就是在棧中多次插入哨兵對(duì)象,而在我們開發(fā)的過程中,通過for循環(huán)加載一些占用內(nèi)存較大的對(duì)象時(shí)可以嵌套使用autoreleasepool,在這些對(duì)象使用完畢的時(shí)候及時(shí)被釋放掉,這樣就不會(huì)造成內(nèi)存過大或過多浪費(fèi)的情況啦~



本文章由作者原創(chuàng),未經(jīng)允許不得轉(zhuǎn)載!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 今天早晨起來心里就悶悶的煩躁,昨天就說好今天陪老二去游泳,一早晨手忙腳亂,折騰到十點(diǎn)半才去,正洗著呢,幼兒園老師...
    薇薇安_b57f閱讀 113評(píng)論 0 0
  • 該是哪一年 他說都已忘了 搔著頭他笑了說 流逝我無知的歲月 時(shí)光的巨流河 河岸婉約的小白楊 齊老爹 他說都已忘了 ...
    其實(shí)我才是王東閱讀 527評(píng)論 0 0
  • 一早到公司,遇到雷姐。她在擺弄安置在辦公桌的一盆植物。她有些沮喪,她說那盆植物看起來像棵蒜,和她預(yù)期差距較大。 我...
    不騖于虛聲閱讀 361評(píng)論 0 1
  • 鯰魚我很愛吃,而且喜歡它肉質(zhì)細(xì)嫩,他在水里的作用是我很多年前就聽說過,由來是因?yàn)樯扯◆~容易缺氧,漁夫在運(yùn)送沙丁魚的...
    NutsVicky閱讀 1,565評(píng)論 0 0

友情鏈接更多精彩內(nèi)容