iOS記憶體管理之:引用計數、ARC、自動釋放池autoreleasepool和便捷方法之間的關係

來源:互聯網
上載者:User

部分內容摘自《Objective-C基礎教程》和互連網

引用計數

       Cocoa採用了引用計數(reference counting)機制,每一個對象有一個關聯的“整數retainCount”用於記錄對象的使用方式。對象被引用時retaincount+1,外部環境結束對象的使用後retainCount-1.當retaincount為0的時候,該對象被銷毀。

        當我們使用alloc、new或者copy的我們需要銷毀這個對象。release函數,只是將對象的retainCount值減1,並不是刪除對象。當retainCount==0的時候,系統會發給對象一個dealloc訊息,另外:千萬不要手動調用dealloc,因為我們不知道何時,何地,何人還會使用該對象。應該老老實實依賴引用計數機制完成記憶體管理。

        釋放對象所有權的函數除了release還有autorelease,這是一種延遲操作,下面會詳細介紹。

        當我們看到下面代碼,

   第一個問題:dateformatter的記憶體管理,應該很好理解,因為[NSDateFormatter alloc]所以,我們要release它。

-(NSString*) date2String:(NSString*)str

{

   
NSString* dateString;

   
NSDate *  currentTime=[NSDate date];

    NSDateFormatter  *dateformatter=[[NSDateFormatter
alloc]
init];

    [dateformatter setDateFormat:str];

    dateString =[dateformatter stringFromDate:currentTime];

    [dateformatter
release];

    return dateString;

}

那麼,這個函數中的NSString* dateStringNSDate * 
currentTime
這兩個變數,在怎樣進行記憶體管理。還有,局部dateString作為傳回值,記憶體管理又是如何?這是個好問題。

        我們發現dateString的賦值方法是 [ dateformatter stringFromDate:current ] ,顯然,它並沒有使用alloc、new或copy任何一種。《Objective-C基礎教程》上說:假設dateString對象被返回時保留引用計數值為1。呵呵,“假設”倆字。這本書還真是基礎教程!

        剛才《Objective-C基礎教程》說過,OC裡沒有棧上對象,沒有臨時對象。那麼這個dateString算是什嗎?

        那麼,現在將他們放到自動釋放的範疇,可以這麼理解:[ dateformatter stringFromDate:current ] 裡面alloc新的對象。這個對象就是autorelease的。

       下面將詳細介紹自動釋放。

自動釋放池autoreleasepool

        自動釋放池是NSAutoreleasePool的執行個體,其中包含了收到autorelease訊息的對象。當一個自動釋放池自身被銷毀(dealloc)時,它會給池中每一個對象發送一個release訊息(如果你給一個對象多次發送autorelease訊息,那麼當自動釋放池銷毀時,這個對象也會收到同樣數目的release訊息)。可以看出,一個自動釋放的對象,它至少能夠存活到自動釋放池銷毀的時候。

        

        簡單的說一個例子,返回局部堆上變數的指標(用c++的口吻說的),那麼這個對象如何釋放?Objective-C發明了自動釋放機制。

-(obj*) foo

{

obj* temp = [[obj alloc]init];

return [ obj autorelease];//只是在返回的時候加上關鍵字autorelease

}

《Objective-C基礎教程》上說:自動釋放(autorelease)是一種延遲釋放機制,這樣保證局部堆上的變數能夠被外部正常使用。

但是,系統又是什麼時候釋放的呢?在每一個事件周期(event cycle)的開始,系統會自動建立一個自動釋放池;

        在每一個事件周期的結尾,系統會自動銷毀這個自動釋放池。一般情況下,你可以理解為:當你的代碼在持續運行時,自動釋放池是不會被銷毀的,這段時間內你也可以安全地使用自動釋放的對象;當你的代碼運行告一段落,開始等待使用者輸入(或者其它事件)時,自動釋放池就會被釋放掉,池中的對象都會收到一個release訊息,有的可能會因此被銷毀。

        這是很難確定的時間,如果自動釋放池的銷毀時間過早,那麼程式就很危險,這個恐怕很難滿足程式員的要求吧。

        自動釋放池的缺點:它延緩了對象的釋放,在有大量自動釋放的對象時,會佔用大量記憶體資源。因此,你需要避免將大量對象自動釋放。並且,在以下兩種情況下,你需要手動建立並手動銷毀掉自動釋放池:

1.當你在主線程外開啟其它線程時:系統只會在主線程中自動產生並銷毀掉自動釋放池。

2.當你在短時間內製造了大量自動釋放對象時:及時地銷毀有助於有效利用iPad上有限地記憶體資源。

     所以,本人不建議使用autorelease的機制,如果遇到上面例子的情況,使用典型的解決方案吧,外部一個對象負責刪除obj對象,防止記憶體泄露。

Convenience method的記憶體管理

        與自動釋放相關的,有一大類構造方法(constructor method),由它們構造的對象直接就是自動釋放的對象;這一類構造方法叫做便捷方法。比如下面這句的字串就是一個自動釋放的對象,stringWithFormat:就是一個便捷方法。

NSString* string = [NSString stringWithFormat:@”autoreleaseString”];

再舉幾個便捷方法的例子,方便讀者以後的開發。

1.NSArrayarrayWithObjects:和arrayWithArray:。

2.UIImageimageNamed:。

3.NSNumbernumberWithBool等。

        也就是說這些方法返回的對象,我們可以用,但是還是不能確定得知道她什麼時候dealloc,那麼我們能不能主動刪除這些“便捷函數”返回的對象呢?如果,程式中有大量的“便捷函數”,這樣無疑佔用了大量記憶體空間。

        難道只能避免迴圈調用這種“便捷函數”?

        現在我們已經解釋了,autorelease方法會在一段時間以後釋放掉一個對象,在這段時間內我們可以安全地使用該對象。那麼這段時間究竟是多久呢?

        上面已經介紹了自動釋放的機制,“便捷函數”產生的對象至少能夠存活到自動釋放池銷毀的時候。

ARC(自動引用計數Auto Reference counting)

        上面的文字介紹了“引用計數”這裡又來個更進階的自動引用計數。

請參考這篇文章 http://blog.csdn.net/zkdemon/article/details/7446385

/****************************************下面說以下典型的應用****************************?

self.xxx的作用。

    NSInteger i =0;

第一行    _extraMessage = [[FtExportMessage
alloc]init];

第二行    //self.extraMessage =
[[FtExportMessage alloc]init];

    i = [self.extraMessage
retainCount];

    [self.extraMessage
release];

你會發現:運行第一行時,retainCount是1,這個好理解。但是不要使用第二行代碼,retaincount是2,及時這個時候你調用release也不會刪除對象。

初學者容易犯錯,什麼地方都用self.XXX.

NSArray和NSDictionary的添加元素,記憶體管理

這種集合類,只是讓“元素”的retainCount加1.同樣,當NSDictionary release的時候,會將“元素”

- (void)prepareData

{

    _buddyMsg   = [[ExportMsgEntity
alloc]
init];

    _pgMsg      = [[ExportMsgEntity alloc] init];;

    _dgMsg      = [[ExportMsgEntity alloc] init];

    _msgGroup = [[NSMutableDictionary
alloc] initWithObjectsAndKeys:

                    
self.buddyMsg,KMsgBuddy,

                    
self.pgMsg,KMsgPGGroup,

                     self.dgMsg,KMsgDGGroup,nil];

   
int i=0;

    i = self.buddyMsg.retainCount;//此時 i=2

}

上面的代碼使self.buddyMsg的retainCount從1加1成為2.那麼,當NSDictionary析構後呢,請看下面的情況

- (void)deleteDictionary

{

    [self.msgGroup
release];

    int i=0;

    i = self.buddyMsg.retainCount;//此時 i=1

}

上面代碼使得self.buddyMsg的retainCount從2減1成為1

總結:使用這些“集合”的時候,不要妄想著“集合”release的時候會自動刪除裡面的元素。最後還是元素自己release資源。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.