了解Cocoa中內(nèi)存如何管理
了解Cocoa中內(nèi)存如何管理是本文要介紹的內(nèi)容,不多說,直接進(jìn)入話題。今天我們來(lái)談?wù)?strong>Cocoa中關(guān)于內(nèi)存管理的問題。這個(gè)問題無(wú)論是對(duì)于桌面開發(fā)還是移動(dòng)開發(fā)都非常重要。
尤其是對(duì)iPhone開發(fā)來(lái)說,更尤為重要。為什么說更呢?因?yàn)閕Phone是移動(dòng)終端,它不會(huì)象Mac一樣有很強(qiáng)的CPU,更不會(huì)有很多的內(nèi)存,這就使iphone程序在內(nèi)存開銷上變得非常昂貴。所以,如果我們不加限制的話,我們的開發(fā)的程序很可能會(huì)使用掉所有的內(nèi)存,這樣我們就沒有空閑的內(nèi)存來(lái)運(yùn)行其他的程序了,誰(shuí)都不想在運(yùn)行程序的時(shí)候接不了電話,對(duì)吧。所以,在這里,我們要強(qiáng)掉內(nèi)存管理的重要性。
當(dāng)然,隨著iPhone的更新?lián)Q代,它的CPU會(huì)越來(lái)越強(qiáng)大,它的內(nèi)存會(huì)越來(lái)越多,即使是這樣我們也要養(yǎng)成良好的編程習(xí)慣,隨時(shí)考慮內(nèi)存問題,開發(fā)出沒有內(nèi)存泄露的完美的程序。
今天,我們將從兩方面討論內(nèi)存這個(gè)問題。
1、如何創(chuàng)建對(duì)象并向它分配內(nèi)存?
2、如何釋放對(duì)象占用的內(nèi)存?
一、如何分配內(nèi)存
我們使用alloc和init方法來(lái)創(chuàng)建對(duì)象并初始化對(duì)象,這其中就包含了向?qū)ο蠓峙鋬?nèi)存。我們看一下下面的代碼。
- Fraction *myFract = [[ Fraction alloc ] init];
其中Fracion是一個(gè)類,上面語(yǔ)句創(chuàng)建了Fraction類的一個(gè)新對(duì)象myFract,并給它分配了內(nèi)存空間用來(lái)存儲(chǔ)在它當(dāng)中的變量。這是一個(gè)很簡(jiǎn)單的語(yǔ)句,在你想給任何一個(gè)類創(chuàng)建新的對(duì)象時(shí),你都可使用這條語(yǔ)句。
還有很多其他的方法可以用來(lái)獲得對(duì)象,就像前面做的一樣,下面是一些例子。
- NSString *newDisplay = [display.text stringByAppendingString:digit];
- NSArray *keys = [dictionary allKeys];
- NSString *lowerString = [string lowercaseString];
- NSNumber *n = [NSNumber numberWithFloat:42.0];
- NSDate *date = [NSDate date];
上面的這些方法都會(huì)獲得對(duì)象,還有很多類似的方法,現(xiàn)在,關(guān)鍵問題出來(lái)了,我們給這些對(duì)象分配了內(nèi)存,那誰(shuí)負(fù)責(zé)釋放他們呢?我們來(lái)看看下面的東西。
二 、內(nèi)存的釋放
好了,我們接著上面留下的問題,為了解決這個(gè)問題,我要介紹下面幾個(gè)概念。
a、引用計(jì)數(shù)器(Reference Counting)
b、引用所有權(quán)(Ownership)
c、自動(dòng)釋放池(Autoreleasepool)
引用計(jì)數(shù)器
我們?cè)谡務(wù)搶?duì)象內(nèi)存的釋放,可到底什么時(shí)候我們需要釋放對(duì)象呢?判斷對(duì)象是否需要釋放的唯一標(biāo)準(zhǔn)是:對(duì)象不再被使用,它在程序中沒有了利用的價(jià)值。我們就是使用引用計(jì)數(shù)器來(lái)判斷對(duì)象在程序中是否還在被使用。
引用計(jì)數(shù)器就是用來(lái)跟蹤對(duì)象的引用次數(shù),它是這樣工作的:當(dāng)一個(gè)對(duì)象被創(chuàng)建時(shí),將它的引用次數(shù)設(shè)置為1,每當(dāng)程序中的其他對(duì)象或方法調(diào)用它時(shí),它的計(jì)數(shù)器就加1。當(dāng)調(diào)用結(jié)束時(shí),計(jì)數(shù)器就減1,這就意味著這個(gè)方法對(duì)對(duì)象的使用結(jié)束了。當(dāng)一個(gè)對(duì)象的計(jì)數(shù)器為0的時(shí)候,表示這個(gè)對(duì)象不被程序中任何其他的對(duì)象和方法調(diào)用,也就是程序不再需要它,這時(shí)候我們就可以安全的釋放它了。
這里面有兩個(gè)非常重要的方法,一個(gè)是retain(保持),另一個(gè)是release(釋放)。當(dāng)對(duì)象被引用時(shí),我們向?qū)ο蟀l(fā)送retain方法,使它的計(jì)數(shù)器加1.當(dāng)引用結(jié)束后,我們向他發(fā)送release方法,使它的計(jì)數(shù)器減1.這樣看來(lái),retain和release方法是成對(duì)出現(xiàn)的,每一個(gè)retain對(duì)應(yīng)一個(gè)release,同理,我們還會(huì)有一個(gè)release方法和計(jì)數(shù)器的初始值1相對(duì)應(yīng),這樣才能保證計(jì)數(shù)器可以減到0,確保對(duì)象可以被釋放。
所有權(quán)(Ownership)
你可能對(duì)上面的介紹感到有些抽象,難于理解。下面我們介紹所有權(quán)的概念,它會(huì)有助于你對(duì)計(jì)數(shù)器的理解。在計(jì)數(shù)器的介紹中我們說一個(gè)對(duì)象被一個(gè)對(duì)象所引用,例如對(duì)象myFract被對(duì)象myNumbe所引用,我們就說myNumbe對(duì)Fract有所有權(quán)。對(duì)應(yīng)的,當(dāng)myNumbe不再使用Fract時(shí),它就要放棄對(duì)Fract的所有權(quán)。當(dāng)程序中沒有對(duì)象和方法對(duì)Fract有所有權(quán)時(shí),對(duì)象Fract就可以被釋放了。這里還要強(qiáng)調(diào)一點(diǎn),一個(gè)對(duì)象可以被多個(gè)對(duì)象或方法所擁有,也就是說程序中可以有多個(gè)對(duì)象或方法同時(shí)對(duì)同一個(gè)對(duì)象擁有所有權(quán)。
好了,接下來(lái)我們把計(jì)數(shù)器和所有權(quán)聯(lián)系在一起。
當(dāng)對(duì)象A被對(duì)象B(或方法)調(diào)用時(shí),對(duì)象B向A發(fā)送retain消息來(lái)獲得對(duì)A的所有權(quán),于此同時(shí)A的計(jì)數(shù)器加1;
當(dāng)B對(duì)A的調(diào)用結(jié)束后,對(duì)象B向A發(fā)送release消息來(lái)放棄對(duì)A的所有權(quán),與此同時(shí)A的計(jì)時(shí)器減1;
當(dāng)A的計(jì)數(shù)器為0時(shí),也就是程序中不再有人對(duì)A有所有權(quán),這時(shí),A就可以被安全的釋放。
現(xiàn)在明白了么?
自動(dòng)釋放池
我們來(lái)說最后一個(gè)概念,我們要把這個(gè)問題和前兩個(gè)概念聯(lián)系在一起,因?yàn)樗鼈兌际荂ocoa內(nèi)存管理的組成部分。我們來(lái)談自動(dòng)釋放池。
系統(tǒng)使用自動(dòng)釋放池來(lái)跟蹤對(duì)象,以便以后釋放它們。有些對(duì)象在你使用完之后,你并不確定你是否還會(huì)再次使用到它,如果這時(shí)候就釋放了,以后在用到它的時(shí)候就會(huì)很麻煩。自動(dòng)釋放池可以解決這個(gè)問題。因?yàn)槟憧梢酝ㄟ^標(biāo)記把對(duì)象添加到自動(dòng)釋放池中,在自動(dòng)釋放池被釋放的時(shí)候,它所包含的對(duì)象也會(huì)被一起釋放。當(dāng)對(duì)象被添加到釋放池中后,它并沒有被釋放,所以你還可以使用它,但你也不用擔(dān)心自己忘記釋放它,應(yīng)為你已經(jīng)把它添加到釋放池中了。
下面這條語(yǔ)句用來(lái)建立釋放池:
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
這條語(yǔ)句用來(lái)釋放自動(dòng)釋放池:
- [pool drain];
要把對(duì)象添加到自動(dòng)釋放池中,可以使用下面的語(yǔ)句:
- [ myFract autorelease] ;
有一點(diǎn)要注意,把對(duì)象添加到釋放池并不會(huì)使對(duì)象的計(jì)數(shù)器加1.
三、內(nèi)存管理規(guī)則摘要
a釋放對(duì)象,可以釋放它所占有的內(nèi)存,如果你的程序在運(yùn)行時(shí)創(chuàng)建了很多對(duì)象,應(yīng)該關(guān)注對(duì)象的釋放,良好的規(guī)則是,不再使用創(chuàng)建或保持的對(duì)象時(shí),就釋放它們。
b發(fā)送一條release消息不一定銷毀對(duì)象,當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)器為0時(shí),才銷毀這個(gè)對(duì)象。系統(tǒng)通過向該對(duì)象發(fā)送一條dealloc消息來(lái)釋放它所占的內(nèi)存。
c自動(dòng)釋放池用于在釋放本身時(shí)自動(dòng)釋放池中的對(duì)象。
d如果你的方法中不再需要一個(gè)對(duì)象,但需要返回它時(shí),那么向其發(fā)送一條autorelease消息,將它標(biāo)記為以后釋放。
e如果使用alloc和copy方法直接創(chuàng)建對(duì)象,則由你負(fù)責(zé)釋放它。每次retain對(duì)象,應(yīng)該release或autorelease它。
小結(jié):了解Cocoa中內(nèi)存如何管理的內(nèi)容介紹完了,以上這些是Cocoa內(nèi)存管理的基本概念,也是最為重要的概念。對(duì)內(nèi)存管理的關(guān)注要貫穿程序開發(fā)的始終,我們要一再的強(qiáng)調(diào)它的重要性。最后希望本文對(duì)你有所幫助!