viewDidLoad中通過NSMutebleArray的array類方法創(chuàng)建數(shù)組對象惧辈,這個array對象的內(nèi)存是在什么時機(jī)釋放的?
在每一次runloop循環(huán)將要結(jié)束時,會對前一次創(chuàng)建的AutoreleasePool進(jìn)行pop操作,同時會push進(jìn)來一個新的AutoreleasePool,所以在viewDidLoad中所創(chuàng)建的array對象,是在當(dāng)次runloop將要結(jié)束
的時候,調(diào)用AutoreleasePoolPage的pop方法中釋放的。
AutoreleasePool的實現(xiàn)原理是怎樣的?
@autoreleasepool{}在編譯器的內(nèi)部實現(xiàn)如下:
//在autoreleasepool中的所有對象,都會添加到自動釋放池中,當(dāng)進(jìn)行pop之后, autoreleasepool中所有對象都會被發(fā)送一次release消息
@ autoreleasepool {
//AutoreleasePoolPage是C++類,調(diào)用它里面的push方法
void *ctx = objc_autoreleasePoolPush(){
void *objc_autoreleasePoolPush(void)
|
void *AutoreleasePoolPage::push(void)
};
//調(diào)用AutoreleasePoolPage中的pop函數(shù),一次pop實際上相當(dāng)于一次批量的pop操作
objc_autoreleasePoolPop(ctx){
void objc_autoreleasePoolPop(void *ctxt)
|
AutoreleasePoolPage::pop(void *ctxt)
};
}
AutoreleasePool為何可以嵌套使用?
自動釋放池的數(shù)據(jù)結(jié)構(gòu)
1.是以棧為結(jié)點(diǎn)通過雙向鏈表的形式組合而成
2.是和線程一一對應(yīng)的
雙向鏈表
黑色箭頭代表父指針
紅色箭頭代表Child指針
Node是一個頭結(jié)點(diǎn),它的父指針指向空,后續(xù)會有各個結(jié)點(diǎn),后續(xù)每個結(jié)點(diǎn)都有兩個指針,父指針指向前一個結(jié)點(diǎn),Child指針指向后一個結(jié)點(diǎn),最后一個指針的Child指針指向一個空結(jié)點(diǎn)磕瓷。
棧是向下增長的,所以下面是高地址,上面是低地址,對棧的操作實際是有入棧和出棧兩種操作盒齿。
棧的特點(diǎn)是后入先出,后加入棧的對象會最先出棧困食。
AutoreleasePoolPage
這個類的主要有四個成員變量
next: 指向棧中下一個可填充的位置边翁。
parent: 雙向鏈表中的父指針。
child: 雙向鏈表中的child指針硕盹。
thread: 說明AutoreleasePool是和線程一一對應(yīng)的符匾。
下圖是AutoreleasePoolPage的一個結(jié)構(gòu)
最下面是自身占用內(nèi)存,上面是用來存儲AutoreleasePool中填充的對象,next指針指向當(dāng)前棧的空位置,若此時進(jìn)行入棧操作,就可以添加到next指針?biāo)赶虻奈恢?/p>
AutoreleasePoolPage中Push方法的內(nèi)部實現(xiàn)
假如next在上圖位置,此時我們push操作,會把當(dāng)前next的位置置為nil,也叫做哨兵對象
,然后將next指針指向下一個可入棧的位置。
實際上每次進(jìn)行AutoreleasePool的代碼塊創(chuàng)建的時候,相當(dāng)于不斷的在棧中去插入哨兵對象瘩例。
[obj autorelease]方法實現(xiàn)
當(dāng)我們調(diào)用了一個對象的autorelease,首先會判斷當(dāng)前next指針是否指向棧頂,若沒有指向棧頂,則直接把對象添加到當(dāng)前棧的next位置啊胶。
假如當(dāng)前next已經(jīng)位于棧頂,那么當(dāng)前AutoreleasePoolPage就沒辦法添加新的autorelease對象了,于是需要增加一個棧結(jié)點(diǎn)拼接到鏈表上,之后再新的棧上面添加對象。
下面看運(yùn)行過程
若此時next指針指向某個位置,若我們添加了新的對象obj(3)(調(diào)用obj(3)的autorelease),放到next位置之后,next指針就會移動到新的位置,再添加新的對象到next位置,next指針繼續(xù)移動到新的位置....
AutoreleasePoolPage中Pop方法的內(nèi)部實現(xiàn)
1.根據(jù)傳入的哨兵對象來找到pop的對應(yīng)位置仰剿。
2.給上次push操作之后添加的對象依次發(fā)送release消息创淡。
- 回退next指針到正確位置。
- 根據(jù)上面的圖,假如此時next指針指向obj(n)的上方,若此時調(diào)用了autoreleasePop操作,是要給紅括號包含的所有對象依次發(fā)送realease消息,假如發(fā)送完,這些對象就會從當(dāng)前棧中清除,清除之后會把next指針指向正確的位置南吮。
總結(jié)
自動釋放池
1.在當(dāng)次runloop將要結(jié)束的時候調(diào)用AutoreleasePoolPage::pop()琳彩。
2.autoreleasePool的多層嵌套調(diào)用就是多次插入哨兵對象,當(dāng)我們每次進(jìn)行autoreleasePool代碼塊創(chuàng)建的時候,系統(tǒng)就會為我們進(jìn)行哨兵對象的插入。
3.autoreleasePool的使用場景: 在for循環(huán)中alloc出大量的圖片數(shù)據(jù)等內(nèi)存消耗較大,需要在for循環(huán)內(nèi)部手動插入autoreleasePool,每一次for循環(huán),都進(jìn)行一次內(nèi)存的釋放,來降低內(nèi)存的峰值部凑。
AutoreleasePool的實現(xiàn)原理
以棧為結(jié)點(diǎn),通過雙向鏈表形式組合而成的一個數(shù)據(jù)結(jié)構(gòu)露乏。