Friday, March 30, 2012

Autorelease, release, retain

在Objective-C中所有的物件都是指標,當我們建立一個物件時(由 alloc、new、copy 產生出來或是使用retain來取得從其他來源獲得的物件),我們不但配置了記憶體,同時也讓該物件的指標指向這個記憶體位址。 Objective-C使用reference counting的方式作為記憶體管理的機制,Reference Counting 的運作是基於 ownership。當程式要使用物件時,必須取得物件的 ownership,一個物件可以有很多 owner;而當程式不再使用物件時,則需要放棄 ownership。直到物件沒有任何 owner 時,物件就會自動被 dealloc。
物件第一次被建立時,只有一個owner的指標指向它的記憶體位址,所以它的reference count為1。若有新owner的指標指向該記憶體,它的reference count便會加1。相反的,如果我們不再需要這個指標,而將它release,該物件的reference count就會減1。當該物件的reference count變為零時,代表沒有指標指向它了,該物件的dealloc函式就會自動被呼叫,這時寫在dealloc裡的那些release指令就會一起被執行了,這塊記憶體就會被釋放掉。


在Objective-C建立物件有兩種方法,一種是手動配置記憶體並初始化該物件:


NSString *string = [[NSString alloc] init];
用這種方式宣告的物件,當我們不再需要使用時,必需手動呼叫release方法來釋放它。


另一種方法則是呼叫該類別的類別方法(Class method)直接建立該物件:


NSString *string = [NSString stringWithFormat:@"test string"];
這類方法所建立的物件我們不需要手動release它,當它被建立的同時,它也會被丟進一個叫做autorelease pool的「池子」裡。每當程式主要的loop執行完一次,就會檢查autorelease pool裡的物件是否還會被使用到,如果會就留著;如果不會就把它清掉。這種會把物件丟進autorelease pool的類別方法有個特點,就是他們的名稱開頭都會是該類別的字串。比如NSString,類別方法中開頭是stringXXX的,就會把建立的物件丟入autorelease pool。


要特別注意的是,autorelease跟release不同,release會馬上在執行後把retain count減1,而autorelease則是待會才會減1。另外,一但你把物件設定為autorelease之後,這個東西基本上就不算是你管的,你之後就不需要也不應該再去對它做release的動作了。


- (NSString *) getBookTitle {  
NSString *name = [[NSString alloc] initWithString:@"This is a book"];  
[name autorelease];  
return name; }


以上的code,因為name這個方法需要回傳值,如果第4行的[name autorelease]寫成了[name release],因為太早release掉name後,name就不會正確回傳了。不加上的話又會造成記憶體的泄漏(leaked)。所以這時候使用了autorelease就是正確的作法。上面的程式碼第2行常常會和autorelease合併簡寫為類似[[[NSString alloc] init] autorelease],或是把第3和4行合併簡寫為return [name autorelease]。



這裡提供幾個基本的原則,希望對還不熟悉記憶體管理的朋友們有些幫助:


  1. 如果是自已alloc或者retain的物件,最後一定要release掉。
  1. 用類別方法(Class method)建立的物件會被丟入autorelease pool,不需要手動釋放記憶體。



Reference:
http://bonjouryentinglai.wordpress.com/2010/02/10/objective-c-隨手筆記-ii-記憶體管理


http://marcelsite.heroku.com/posts/5-iPhone-s-alloc-init-new-retain-release-autorelease-copy-


http://log.bcse.tw/2011/05/ios-programming-tips-3.html

No comments:

Post a Comment