34.以“自動釋放池塊”降低內存峰值

《編寫高質量iOS與OS X代碼的52個有效方法》--第五章 第34條
(ps:此乃讀書筆記,加深記憶,僅供大家參考)


第34條 以“自動釋放池塊”降低內存峰值

Objective-C對象的生命期取決于其引用計數。釋放對象有兩種方式:一種是調用release方法,使其保留計數立即遞減;另一種是調用autorelease方法,將其加入“自動釋放池”中。自動釋放池用于存放那些需要在稍后某個時刻釋放的對象。

創(chuàng)建自動釋放池所用語法如下:

@autoreleasepool {
    //...
}

一般情況下無須擔心自動釋放池的創(chuàng)建問題。Mac OS X與iOS應用程序分別運行于Cocoa及Cocoa Touch環(huán)境中。系統(tǒng)會自動創(chuàng)建一些線程,比如說主線程或是“大中樞派發(fā)”(Grand Central Dispatch,GCD)機制中的線程,這些線程默認都有自動釋放池,每次執(zhí)行“事件循環(huán)”(event loop)時,就會將其清空。通常只有一個地方需要創(chuàng)建自動釋放池,那就是main函數里,我們用自動釋放池來包裹應用程序的主入口點(main application entry point)。

int main(int argc, char * argv[]) {
@autoreleasepool {
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

塊的末尾恰好就是應用程序的終止處,而此時操作系統(tǒng)會把程序所占的全部內存都釋放掉。但是如果不寫這個塊的話,那么由UIApplicationMain函數所自動釋放的那些對象,就沒有自動釋放池可以容納了,于是系統(tǒng)會發(fā)出警告信息來表明這一情況。所以說,這個池可以理解成最外圍捕捉全部自動釋放對象所用的池。

自動釋放池于左花括號處創(chuàng)建,并于對應的右花括號處自動清空。位于自動釋放池范圍內的對象,將在此范圍末尾處收到release消息。自動釋放池可以嵌套。

@autoreleasepool {
    NSString *string = [NSString stringWithFormat:@"1 = %i", 1];
    @autoreleasepool {
        NSNumber *number = [NSNumber numberWithInt:1];
    }
}

將自動釋放池嵌套的好處是,可以借此控制應用程序的內存峰值,使其不致過高。

for (int i = 0; i < 1000; i++) {
    [self doSomethingWithInt:i];
}

如果“doSomethingWithInt:”方法要創(chuàng)建臨時對象,那么這些對象很可能會放在自動釋放池里。然而釋放池要等線程執(zhí)行下一次事件循環(huán)時才會清空。這就意味著在執(zhí)行for循環(huán)時,會持續(xù)有新對象創(chuàng)建出來,并加入自動釋放池中。所有這種對象都要等for循環(huán)執(zhí)行完才會釋放。這樣一來,在執(zhí)行for循環(huán)時,應用程序所占內存量就會持續(xù)上漲,而等到所有臨時對象都釋放后,內存量又會突然降下來。

如果把循環(huán)內的代碼包裹在“自動釋放池塊”中,那么在循環(huán)中自動釋放的對象就會放在這個池,而不是線程的主池里面。

NSArray * databaseRecords = /* . . . */;
NSMutableArray *people = [NSMutableArray new];
for (NSDictionary *record in databaseRecords) {
    @autoreleasepool {
        EOCPerson * person = [[EOCPerson alloc] initWithRecord:record];
        [people addObject:person];
    }
}

加上這個自動釋放池之后,應用程序在執(zhí)行循環(huán)時的內存峰值就會降低,不再像原來那么高了。內存峰值(high-memory waterline)是指應用程序在某個特定時段內的最大內存用量(highest memory footprint)。

自動釋放池機制就像“棧”(stack)一樣。系統(tǒng)創(chuàng)建好自動釋放池之后,就將其推入棧中,而清空自動釋放池,則相當于將其從棧中彈出。在對象上執(zhí)行自動釋放操作,就等于將其放入棧頂的那個池里。

盡管自動釋放池塊的開銷不太大,但畢竟還是有的,所以盡量不要建立額外的自動釋放池。

@autoreleasepool語法還有個好處:每個自動釋放池均有其范圍,可以避免無意間誤用了那些在清空池厚已為系統(tǒng)所回收的對象。

要點

  • 自動釋放池排布在棧中,對象收到autorelease消息后,系統(tǒng)將其放入最頂端的池里。
  • 合理運用自動釋放池,可降低應用程序的內存峰值。
  • @autoreleasepool這種新式寫法能創(chuàng)建出更為輕便的自動釋放池。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容