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