Autorelease Pools

 http://hi.baidu.com/zijian0428/item/c1e1df17542a2e4ae65e0628

http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html#//apple_ref/doc/uid/20000047-SW2

 Objective-C Autorelease Pools(自動釋放池)詳解
 本篇將給您介紹”Autorelease Pools”(自動釋放池)在應用中的使用技巧。

1,Autorelease Pools概要
一個”AutoreleasePool”實例中“包含”其它各種調用了”autorelease”方法的對象。當它釋放時,其中所有被管理對象都會收到”relrease”的消息。注意,同一個對象可以被多次調用”autorelease”方法,並可以放到同一個”AutoreleasePool”中。引入這個自動釋放池機制,對象的”autorelease”方法代替”relrease”方法可以延長它的生命週期,直接到當前”AutorelreasePool”釋放。如果想讓此對象的生命週期超過”Autorelease Pool”,還可以再次”retain”,呵呵,有意思吧〜且讓我慢慢道來。

Cocoa總是認爲當前至少有一個”AutoreleasePool”對象是可用的。若此對象並不存在,你調用的”autorelease”的所有對象都不會被自動釋放掉,可想而知,造成內存泄露。Cocoa把這個錯誤信息寫入日誌〜〜僅僅是爲了以後分析。

你可以用”alloc”與”init”方法創建一個”NSAutoreleasePool”對象,並且可以調用”release”或”drain”(”release”與”drain”的區別是”drain”在有GC的環境中會引起GC回收操作,”release”反之。但在非GC環境中,兩者相同。官方的說法是爲了程序的兼容性,應該考慮用”drain”代替”release”,)方法來回收它(調用它的”autorelease”或”retain”方法會引起異常)。在一個完整的上下文最後”Autorelease Pool”對象應該被”release”掉(在方法內或一段循環體內創建的”Autorelease Pool”對象)。

“AutoreleasePools”的所有實例在棧中管理(我們暫時叫他“自動釋放池棧”),並且它們是可以被嵌套的(父生子,子生孫。。。子子孫孫^_^)。例如,當我們創建一個”AutoreleasePool”對象後,它就被自動放到“自動釋放池棧”的棧頂。當本池對象回收時,它就隨之從這個棧中POP掉。那麼也就是說,當任何一個對象調用”autorelease”方法後,它會被放入當前線程中當前棧頂的自動釋放池中。

接下來我們聊聊”AutoreleasePools”的嵌套問題。在你的應用中,你可以任意多的創建”AutoreleasePool”對象,而這些對象被當前線程的“自動釋放池棧”所管理。那麼除了一個接一個的順序創建並銷燬它的情況外,還有一種使用方式,就是嵌套式的創建與使用。例如:在你的主函數創建了一個”autoreleasepool”,然後又調用了創建了”autoreleasepool”實例的其它方法;或是在外循環中創建了”AutoreleasePool”的實例,而內循環中也做了相同的事情。有意思吧,呵呵,嵌套的機制使父Pool實例釋放後,它的所有子Pool也將釋放。但這裏還存在一些副作用,後續文章會詳細討論。

“Applicationkit”在一個事件循環裏會自動創建一個”autoreleasepool”。像鼠標鍵的按下與釋放,所以你編寫的代碼通常不需要考慮太多這方面的事情。當然,有以下三種情況你會創建與銷燬自己的Pool實例:
   1,應用不是基於”Application Kit”,像”Command-line tool”,因爲它並沒有內置的”autorelease pools”的支持。
   2,創建線程,你必需在線程開始時創建一個”Autorelease Pool”實例。反之,會造成內存池露(會在以後的文章詳細說明線程與池的技巧)。
   3,一個循環內創建了太多的臨時對象,你應該爲他們創建一個”Autorelease Pool”對象,並在下次循還前銷燬它們。

2,自動釋放池中的”Non-AppKit”應用
在”Non-AppKit”應用中使用自動釋放池的機制其實是相當簡單的事情。你僅僅需要在main()起始處創建”AutoreleasePool”對象,並在結尾處釋放掉它。就像在Xcode的FoundationTool的創建模版裏寫的一樣。這個確保你在應用生命週期內至少有一個”AutoreleasePool”是可用的。但是,這也使所有在此期間的所有”autorelease”的對象都必需在應用結束後才被釋放。這也許會引起在應用的使用中不斷的增長,所以,你仍然考慮在不同的作用域創建新的”Autorelease Pool”。

大多應用中都存在各種級別的循環機制。在這些應用中,你可以在每個循環內的開頭創建一個”Autorelease Pool”對象,並在結尾處釋放掉它。

例如:

void main()
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSArray *args = [[NSProcessInfo processInfo] arguments];
    unsigned count, limit = [args count];

    for (count = 0; count < limit; count++)
    {
        NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
        NSString *fileContents;
        NSString *fileName;

        fileName = [args objectAtIndex:count];
        fileContents = [[[NSString alloc] initWithContentsOfFile:fileName] autorelease];
        // this is equivalent to using stringWithContentsOfFile:
        /* Process the file, creating and autoreleasing more objects. */

        [loopPool release];
    }

    /* Do whatever cleanup is needed. */
    [pool drain];

    exit (EXIT_SUCCESS);
}

在命令行中處理所有以參數傳來的文件。一次循環處理一個文件。在循環的開頭創建一個”NSAutoreleasePool”對象,並在循環結束時釋放掉。因此,任何在其中創建並調用“autorelease”的對象都將添加到這個Pool實例中,當本池被釋放後,這些對象也將被回收。注意,任何在作用域內創建的”autoreleased”對象(像”fileName”),雖然並沒有顯示的調用”autorelease”方法,但都將被當前池所管理並釋放。

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