autorelease

總覺得autorelease這裏掌握的不到位,但涉及到內存管理,實在不可小視。今天參考了網上的不少文章和官方API文檔,做了如下總結。

1、autorelease是什麼?

autorelease是一種支持引用計數的內存管理方式

它可以暫時的保存某個對象(object),然後在內存池自己的排幹(drain)的時候對其中的每個對象發送release消息

注意,這裏只是發送release消息,如果當時的引用計數(reference-counted)依然不爲0,則該對象依然不會被釋放。可以用該方法來保存某個對象,也要注意保存之後要釋放該對象。

autorelease可以通過NSAutoreleasePool創建實例

 

2、爲什麼會有autorelease?

OC的內存管理機制中比較重要的一條規律是:誰申請,誰釋放

考慮這種情況,如果一個方法需要返回一個新建的對象,該對象何時釋放?

方法內部是不會寫release來釋放對象的,因爲這樣做會將對象立即釋放而返回一個空對象;調用者也不會主動釋放該對象的,因爲調用者遵循“誰申請,誰釋放”的原則。那麼這個時候,就發生了內存泄露。

針對這種情況,Objective-C的設計了autorelease,既能確保對象能正確釋放,又能返回有效的對象。

在autorelease的模式下,下述方法是合理的,即可以正確返回結果,也不會造成內存泄露

ClassA *Func1()

{

 ClassA *obj = [[[ClassA alloc]init]autorelease];

 return obj;

}

 

3、autorelease是什麼原理?

Autorelease實際上只是把對release的調用延遲了,對於每一個Autorelease,系統只是把該Object放入了當 前的Autorelease pool中,當該pool被釋放時,該pool中的所有Object會被調用Release。

 

4、autorelease何時釋放?

對於autorelease pool本身,會在如下兩個條件發生時候被釋放(詳細信息請參見第5條)

1)、手動釋放Autorelease pool

2)、Runloop結束後自動釋放

對於autorelease pool內部的對象

在引用計數的retain == 0的時候釋放。release和autorelease pool 的 drain都會觸發retain--事件。

 

5、autorelease釋放的具體原理是什麼?

要搞懂具體原理,則要先要搞清楚autorelease何時會創建。

我們的程序在main()調用的時候會自動調用一個autorelease,然後在每一個Runloop, 系統會隱式創建一個Autorelease pool,這樣所有的release pool會構成一個象CallStack一樣的一個棧式結構,在每一個Runloop結束時,當前棧頂的 Autorelease pool(main()裏的autorelease)會被銷燬,這樣這個pool裏的每個Object會被release。

可以把autorelease pool理解成一個類似父類與子類的關係,main()創建了父類,每個Runloop自動生成的或者開發者自定義的autorelease pool都會成爲該父類的子類。當父類被釋放的時候,沒有被釋放的子類也會被釋放,這樣所有子類中的對象也會收到release消息。

那什麼是一個Runloop呢? 一個UI事件,Timer call, delegate call, 一個鼠標事件,鍵盤按下(MAC OSX),或者iphone上的觸摸事件,異步http連接下後當接收完數據時,都會是一個新的Runloop。

一般來說,消息循環運行一次是毫秒級甚至微秒級的,因此autorelease的效率仍然是非常高的,確實是一個巧妙的設計。

 

 

6、使用有什麼要注意的?

1)、NSAutoreleasePool可以創建一個autorelease pool,但該對象本身也需要被釋放,如:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init;

// Code benefitting from a local autorelease pool.

[pool release];

在引用計數環境下,使用[pool release]或[pool drain]效果是相同的,drain僅適用於max os高版本,低版本不適用,而release通用,其它並無太大差別。

2)、在ARC下,不能使用上述方式調用autorelease,而應當使用@autoreleasepool,如:

@autoreleasepool {

   // Code benefitting from a local autorelease pool.

}

3)、儘量避免對大內存使用該方法,如圖片。對於這種延遲釋放機制,還是儘量少用,最好只用在方法內返回小塊內存申請地址值的情況下,且

參考和領會OC的一些系統方法,如:[NSString stringWithFormat:]

4)、不要把大量循環操作放到同一個NSAutoreleasePool之間,這樣會造成內存峯值的上升。

 

7、關於多線程,有什麼要注意的?

我還未實際使用到,在官方API翻譯出類似如下語句:

1)、對於不同線程,應當創建自己的autorelease pool。如果應用長期存在,應該定期drain和創建新的autorelease pool

下面這句話摘自官方API,大概是說多線程中如果沒有使用到cocoa的相關調用,則不需要創建autorelease pool,我一直沒有理解透徹

If, however, your detached thread does not make Cocoa calls, you do not need to create an autorelease pool.

 

2)、如果不是使用的NSThread,就不要用aoturelease pool,除非你是多線程模式(multithreading mode) ,可以使用NSThread的isMultiThreaded方法測試你的應用是否是多線程模式

詳細可以參考官方API的NSAutoreleasePool Class Reference


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章