@autoreleasepool-內存的分配與釋放

@autoreleasepool-內存的分配與釋放

開發過iOS、Mac的朋友應該對「 @autoreleasepool 」不陌生。只要在Xcode裏建立一個工程,就能看到下面這樣的代碼:

//iOS program
int main(int argc, char * argv[]) {
  @autoreleasepool {
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}
//Command line program
int main(int argc, const char *argv[]) {
  @autoreleasepool {
    //...
  }
  return 0;
}

看,每一個 main 函數的主體都被 @autoreleasepool 的Block塊包在裏面,也就是說,接下來全部的對象建立都在這個block裏面。

那麼, @autoreleasepool 的做用究竟是什麼呢?咱們開發中能夠用它來作什麼呢?

能夠在某些狀況下,大幅度下降程序的內存佔用,以下圖:


測試的內容:500000次循環,每次循環建立一個NSNumber實例和兩個NSString實例。
圖:紅線表示沒有用 @autoreleasepool 時的內存佔用。
圖:綠線表示用了 @autoreleasepool 優化後的內存佔用!
效果是否是很明顯!

代碼Github地址: AutoReleasePoolTestExample Xcode 6, iOS 8, iPhone 5模擬器.

MRC 與 ARC

MRC(Mannul Reference Counting)和ARC(Automatic Reference Counting),分別對應着手動引用計數和自動引用計數。

對!是計數,不是「 GC、垃圾回收 」什麼的,就是說,在Objective-C的開發中,ARC不表明像Java那樣有GC作垃圾回收,因此本質上仍是要「手動」管理內存的。也就是說,咱們在ARC環境下寫的代碼,不用本身手動插入「 retain、release這些消息 」,ARC會在編譯時爲咱們在合適的位置插入,釋放沒必要要的內存。

而 @autoreleasepool 就跟對象的 release 密切相關。

@autoreleasepool 幹了啥

在MRC時代,若是咱們想先retain一個對象,可是並不知道在何時能夠release它,咱們能夠像下面這麼作:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSString* str = [[[NSString alloc] initWithString:@"tutuge"] autorelease];
//use str...

[pool release];
//str is released
就是說,咱們能夠在建立對象的時候給對象發送「 autorelease 」消息,而後當 NSAutoreleasePool 結束的時候,「標記過」autorelease的對象都會被「 release 」掉,也就是會被釋放掉。

可是在ARC時代,咱們不用手動發送 autorelease 消息,ARC會自動幫咱們加。而這個時候, @autoreleasepool 作的事情,跟 NSAutoreleasePool 就如出一轍了。

何時用@autoreleasepool

根據 Apple的文檔 ,使用場景以下:

寫基於命令行的的程序時,就是沒有UI框架,如AppKit等Cocoa框架時。
寫循環,循環裏面包含了大量臨時建立的對象。(本文的例子)
建立了新的線程。(非Cocoa程序建立線程時才須要)
長時間在後臺運行的任務。
利用@autoreleasepool優化循環

利用@autoreleasepool優化循環的內存佔用,我以爲最有用的一點,下面就說說這個點。

以下面的循環,次數很是多,並且循環體裏面的對象都是臨時建立使用的,就能夠用 @autoreleasepool 包起來,讓每次循環結束時,能夠及時的釋放臨時對象的內存。

//來自Apple文檔,見參考
NSArray *urls = <# An array of file URLs #>;
for (NSURL *url in urls) {
  @autoreleasepool {
    NSError *error;
    NSString *fileContents = [NSString stringWithContentsOfURL:url
                     encoding:NSUTF8StringEncoding error:&error];
    /* Process the string, creating and autoreleasing more objects. */
  }
}

這麼作的效果是極其顯著地,就如本文最開始的圖同樣,能夠本身把示例工程下回來運行下試試~

總結

@autoreleasepool看起來很不「起眼」,日常開發很容易就忽略它了,可是仔細一看,確如此有用~

參考
相關文章
相關標籤/搜索