例子1
一個(gè)老程序員,功成名就,金盆洗手不在寫代碼后,決定練練書法。提筆思索良久后在紙上寫下:Hello world!
for (int i = 0 ; i < largeNumber; i++) {
NSString *myStr = @"Hello world"; // 原諒我用Hello world
myStr = [myStr stringByAppendingString:[NSString stringWithFormat:@"-%05d-",i]];
}
那么會(huì)有什么問題呢?
如果largeNumber不大時(shí)沒有問題,但是當(dāng)它很大時(shí)問題非常嚴(yán)重!造成內(nèi)存泄露。雖然ARC會(huì)自動(dòng)釋放內(nèi)存,但是ARC內(nèi)存的釋放,即全局的自動(dòng)釋放池是當(dāng)完成一次消息循環(huán)才會(huì)釋放。當(dāng)我們使用for循環(huán)創(chuàng)建很多個(gè)使用autorelease方式創(chuàng)建的NSString對(duì)象的時(shí)候,將所有的對(duì)象的釋放權(quán)都交給了一個(gè)全局的釋放池(RunLoop 的釋放池),而RunLoop的釋放池會(huì)等待這個(gè)事件處理之后才會(huì)釋放,因此就會(huì)使對(duì)象無法及時(shí)釋放,堆積在內(nèi)存造成內(nèi)存泄露。
代碼應(yīng)該這樣修改:添加一個(gè)局部的自動(dòng)釋放池,那么每執(zhí)行一次循環(huán)就會(huì)釋放一次,則不會(huì)造成內(nèi)存泄露
for (int i = 0 ; i < largeNumber; i++) {
@autoreleasepool {
NSString *myStr = @"Hello world";
myStr = [myStr stringByAppendingString:[NSString stringWithFormat:@"-%05d-",i]];
}
}
例子2
我們來看一個(gè)自動(dòng)釋放的例子。一個(gè)所有者先用alloc方法創(chuàng)建一個(gè)對(duì)象;此時(shí)該所有者擁有這個(gè)對(duì)象,對(duì)象的引用計(jì)數(shù)為1。緊接著,所有者自動(dòng)釋放該對(duì)象;所有者此時(shí)已經(jīng)放棄了所有權(quán),但對(duì)象的引用計(jì)數(shù)在一段時(shí)間內(nèi)依然為1。我們可以看出自動(dòng)釋放的另一個(gè)好處:你不會(huì)因?yàn)樵诤竺嫱浗o對(duì)象發(fā)送release消息而造成內(nèi)存泄露。
- (Object *)returnAutoreleaseObject
{
Object *obj = [[Object alloc] init];
return [obj autorelease];
}
現(xiàn)在我們已經(jīng)解釋了,autorelease方法會(huì)在一段時(shí)間以后釋放掉一個(gè)對(duì)象,在這段時(shí)間內(nèi)我們可以安全地使用該對(duì)象。那么這段時(shí)間究竟是多久呢?
我們需要先更多地了解自動(dòng)釋放的機(jī)制,再來回答這個(gè)問題。讓我們先來看看自動(dòng)釋放池。自動(dòng)釋放池是NSAutoreleasePool的實(shí)例,其中包含了收到autorelease消息的對(duì)象。當(dāng)一個(gè)自動(dòng)釋放池自身被銷毀(dealloc)時(shí),它會(huì)給池中每一個(gè)對(duì)象發(fā)送一個(gè)release消息(如果你給一個(gè)對(duì)象多次發(fā)送autorelease消息,那么當(dāng)自動(dòng)釋放池銷毀時(shí),這個(gè)對(duì)象也會(huì)收到同樣數(shù)目的release消息)。可以看出,一個(gè)自動(dòng)釋放的對(duì)象,它至少能夠存活到自動(dòng)釋放池銷毀的時(shí)候。那么自動(dòng)釋放池何時(shí)被創(chuàng)建,又何時(shí)被銷毀呢?在每一個(gè)事件周期(event cycle)的開始,系統(tǒng)會(huì)自動(dòng)創(chuàng)建一個(gè)自動(dòng)釋放池;在每一個(gè)事件周期的結(jié)尾,系統(tǒng)會(huì)自動(dòng)銷毀這個(gè)自動(dòng)釋放池。一般情況下,你可以理解為:當(dāng)你的代碼在持續(xù)運(yùn)行時(shí),自動(dòng)釋放池是不會(huì)被銷毀的,這段時(shí)間內(nèi)你也可以安全地使用自動(dòng)釋放的對(duì)象;當(dāng)你的代碼運(yùn)行告一段落,開始等待用戶輸入(或者其它事件)時(shí),自動(dòng)釋放池就會(huì)被釋放掉,池中的對(duì)象都會(huì)收到一個(gè)release消息,有的可能會(huì)因此被銷毀。到此為止,相信你已經(jīng)對(duì)自動(dòng)釋放的機(jī)制有了一個(gè)大體的了解。自動(dòng)釋放而非直接釋放,可以幫助你節(jié)省一些代碼量,提高開發(fā)速度。但是它有一個(gè)直接的缺點(diǎn):它延緩了對(duì)象的釋放,在有大量自動(dòng)釋放的對(duì)象時(shí),會(huì)占用大量?jī)?nèi)存資源。因此,你需要避免將大量對(duì)象自動(dòng)釋放。并且,在以下兩種情況下,你需要手動(dòng)建立并手動(dòng)銷毀掉自動(dòng)釋放池: 1.當(dāng)你在主線程外開啟其它線程時(shí):系統(tǒng)只會(huì)在主線程中自動(dòng)生成并銷毀掉自動(dòng)釋放池。 2.當(dāng)你在短時(shí)間內(nèi)制造了大量自動(dòng)釋放對(duì)象時(shí):及時(shí)地銷毀有助于有效利用iPad上有限地內(nèi)存資源。