前言
寫此文章是因?yàn)楹芫弥暗囊淮蚊嬖嚕嬖嚬賳栁褹utoreleasePool用的多不多沪伙,當(dāng)時(shí)距離上次工作有些時(shí)日瓮顽,又一直在家?guī)Ш⒆樱蝗蝗ノ穑悬c(diǎn)懵暖混,現(xiàn)在來復(fù)習(xí)下吧
正文
AutoreleasePool:自動(dòng)釋放池,雙向鏈表結(jié)構(gòu)某饰,在代碼中會(huì)被解析成如下這樣
void *context = objc_autoreleasePoolPush();
// {}中的代碼
objc_autoreleasePoolPop(context);//當(dāng)前runloop迭代結(jié)束時(shí)進(jìn)行pop操作
這兩個(gè)函數(shù)實(shí)際上都是對(duì)AutoreleasePoolPage的封裝儒恋,參考sunnyxx的博客,AutoreleasePoolPage的結(jié)構(gòu)如下:
AutoreleasePool是按線程一一對(duì)應(yīng)的(結(jié)構(gòu)中的thread指針指向當(dāng)前線程)
AutoreleasePool本身并沒有單獨(dú)的結(jié)構(gòu)黔漂,其本質(zhì)是由若干個(gè)AutoreleasePoolPage以雙向鏈表形式組成,每個(gè)AutoreleasePoolPage則是棧結(jié)構(gòu)禀酱,而next指向當(dāng)前棧頂?shù)南聜€(gè)位置炬守,即指向棧頂最新add進(jìn)來的autorelease對(duì)象的下一個(gè)位置
AutoreleasePoolPage每個(gè)對(duì)象會(huì)開辟4096字節(jié)內(nèi)存(也就是虛擬內(nèi)存一頁的大小)剂跟,除了上面的實(shí)例變量所占空間减途,剩下的空間全部用來儲(chǔ)存autorelease對(duì)象的地址
添加對(duì)象的時(shí)候,一個(gè)AutoreleasePoolPage的空間被占滿時(shí)曹洽,會(huì)新建一個(gè)AutoreleasePoolPage對(duì)象鳍置,連接鏈表,后來的autorelease對(duì)象在新的page加入送淆,與這一頁鏈表連接完成后税产,新page的next指針被初始化在棧底(begin的位置),然后繼續(xù)向棧頂添加新對(duì)象偷崩。
再說說AutoreleasePool的釋放時(shí)機(jī)辟拷,可以分為兩種情況:一是系統(tǒng)添加的,那么則跟隨當(dāng)前線程的runloop阐斜,runloop結(jié)束時(shí)釋放衫冻,因?yàn)榫幾g器在每個(gè)runloop中開始時(shí)加入了自動(dòng)釋放池的Push和結(jié)束時(shí)加入了Pop;二是手動(dòng)添加的谒出,那就是在{}結(jié)束時(shí)就釋放啦隅俘,出了作用域。
其他Autorelease相關(guān)知識(shí)點(diǎn)
使用容器的block版本的枚舉器時(shí)笤喳,內(nèi)部會(huì)自動(dòng)添加一個(gè)AutoreleasePool:
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// 這里被一個(gè)局部@autoreleasepool包圍著
}];
當(dāng)然为居,在普通for循環(huán)和for in循環(huán)中沒有,所以莉测,還是新版的block版本枚舉器更加方便颜骤。for循環(huán)中遍歷產(chǎn)生大量autorelease變量時(shí),就需要手加局部AutoreleasePool咯