「都已經是 ARC 時代了,為什麼還要使用 @autoreleasepool?」
這是我常被後輩問到的問題。明明是在某處看過的關鍵字,但要立即回答何時以及為什麼使用,意外地不容易。
今天會從@autoreleasepool是什麼開始,一路說明實務上何時該使用它。
先說結論。
@autoreleasepool是一個區塊,能在你指定的時間,提前釋放那些「預約稍後釋放的物件」。在迴圈中大量產生暫存物件時,防止記憶體暴增是它最典型的用途。
我們逐一來看。
什麼是自動釋放池?
先從背景概念開始。
Objective-C很早以前就有autorelease這項機制。它會把物件預約成「現在先不要,過一會兒再release」。
這些已預約物件排隊等待的清單,就是 autorelease pool。
當 pool 被 drain 的瞬間,清單中的物件會一次收到 release。
那麼,這個 pool 什麼時候會被清空呢?
在 iOS App 中,主執行迴圈會自動管理。每次完成一個週期——處理觸控事件再更新畫面——就會將 pool 徹底清空。
所以平常不需要特別操心。
問題會在迴圈中爆發
不過,「每次週期結束時」這個條件,在某些情況下反而會造成問題。
也就是在一次執行迴圈運轉期間,累積了大量暫存物件。
例如,假設在一個迴圈中處理數千張照片。
for (int i = 0; i < 5000; i++) {
// 每次都會暫時建立大型影像物件
UIImage *image = [self loadAndResizeImage:i];
[self saveThumbnail:image];
}
迴圈執行期間,執行迴圈根本沒有機會清空 pool。
因此,只設定等待釋放的暫存物件,會完整累積相當於 5,000 張照片的記憶體。
記憶體圖表像山一樣急升,嚴重時系統甚至會強制終止 App。
用 @autoreleasepool 剷平這座山
解法很簡單:在迴圈內建立專用的 pool,每跑一圈就自行清空。
for (int i = 0; i < 5000; i++) {
@autoreleasepool {
UIImage *image = [self loadAndResizeImage:i];
[self saveThumbnail:image];
} // 區塊結束的瞬間,暫存物件就會立即釋放
}
@autoreleasepool區塊關閉的瞬間,區塊內建立的暫存物件就會立即整理。
不再是累積相當於 5,000 張照片的記憶體後一次釋放,而是每次累積一張、釋放一張。
原本山形的記憶體圖表會變成平緩的鋸齒形。
在 Swift 中這樣使用
你可能會說:「我只使用 Swift 耶?」Swift 也有完全相同的工具。
就是autoreleasepool函式。
for i in 0..<5000 {
autoreleasepool {
let image = loadAndResizeImage(i)
saveThumbnail(image)
}
}
有一點需要注意。
純 Swift 物件大多不會經過 autorelease pool,作用域結束時就會立即釋放。
這項工具真正發揮作用的時機,是重複呼叫UIImage、Data(contentsOf:)、NSData等以 Objective-C 為基礎的 Foundation・UIKit API。
因為現在仍有許多 API 會在內部建立並回傳 autorelease 物件。
這些情況就該使用
總結來說,需要使用@autoreleasepool的時機包括以下情況。
- 在迴圈中大量建立影像、檔案、字串等大型暫存物件時
- 在背景執行緒中,沒有執行迴圈卻長時間執行工作時
- 在命令列工具等沒有執行迴圈的環境中使用 Objective-C 物件時
反過來說,平常的 UI 程式碼和一般商業邏輯不需要特別使用。因為主執行迴圈已經管理得很好。
也不建議沒有量測就習慣性地包起來。應該先在 Instruments 或 Xcode 記憶體圖表中確認實際出現尖峰,再決定使用。
常見問題(Q&A)
Q. ARC 會自動處理,為什麼還要由我管理 pool?
ARC(Automatic Reference Counting,自動參考計數)只會代替你插入 retain・release,並不會改變 autorelease pool 何時清空。提前清空 pool 的「時機」,仍然是開發者的責任。
Q. main 函式中的 @autoreleasepool 是什麼?
開啟 Objective-C 專案的 main.m,會看到整個 App 都包在@autoreleasepool中,這就是 App 的最上層 pool。執行迴圈會在其中運作,並在每個週期清空子 pool。
Q. 可以巢狀使用區塊嗎?
可以。pool 會像堆疊一樣逐層堆疊。內層區塊關閉時,只會清空內層 pool,外層 pool 會維持原狀。
簡單總結,@autoreleasepool就是一個能在指定時機清空「已預約釋放的暫存物件」的區塊。
如果你用 Instruments 確認迴圈中的記憶體像山一樣暴增,請試著用這個區塊包住迴圈內部。你會清楚看到圖表變得平穩。
如果你對從 MRC(Manual Reference Counting,手動參考計數)轉向 ARC 的歷史感興趣,也推薦閱讀之前整理的「Objective-C 記憶體管理歷史」。祝你今天也享受寫程式!

