今天我們將深入探討 iOS 記憶體管理的核心機制——自動引用計數(Automatic Reference Counting, ARC)。我們將通過一個「吃掉記憶體」的實驗來觀察當強引用(strong reference)導致循環引用(retain cycle)時,記憶體如何被耗盡,並學習如何正確地解決這個問題以避免記憶體洩漏。
我們將進行兩個實驗:
首先,我們會創建兩個物件(Person 和 Apartment),並讓它們互相持有強引用。即便我們將它們設為 nil,由於彼此間存在強引用,記憶體將無法釋放,最終導致記憶體洩漏。
class Person {
let name: String
var apartment: Apartment? // 強引用
init(name: String) { self.name = name }
}
class Apartment {
let unit: String
var tenant: Person? // 強引用
init(unit: String) { self.unit = unit }
}
func testARC() {
var jason: Person? = Person(name: String(repeating: "Jason", count: 1000000))
var unit4A: Apartment? = Apartment(unit: "4A")
jason?.apartment = unit4A
unit4A?.tenant = jason
jason = nil
unit4A = nil
}
可以看到,無論我們將 jason 和 unit4A 設為 nil,由於它們互相強引用,記憶體無法釋放,這導致了記憶體洩漏。
執行後可以看到模擬器記憶體使用量持續上升,截圖顯示已經達到14GB,且繼續增加,這是典型的記憶體洩漏案例。
在第二個實驗中,我們將修改其中一個引用為弱引用(weak reference),從而打破循環引用,確保記憶體能夠被正確釋放。
class Apartment {
let unit: String
weak var tenant: Person? // 弱引用,避免循環引用
}
這次,當我們將 jason 和 unit4A 設為 nil 時,記憶體得以順利釋放。透過 Instruments 或 Xcode 工具可以看到記憶體不再持續上升,且無記憶體洩漏發生。
從下圖可以看見記憶體順利被釋放。
在 Xcode 中,選擇 Product > Profile,並選擇 Allocations 模板來檢測記憶體使用情況。或者,點擊 Memory Report 裡的「Profile in Instruments」按鈕,也可以打開 Instruments 來進行詳細檢查。
當檢測到記憶體洩漏時,會在 Instruments 中出現紅色的警示符號,如下圖所示:
在這篇文章中,我們學習了 自動引用計數(ARC) 的基本工作原理,並通過實驗展示了強引用導致的循環引用問題以及如何使用弱引用來避免記憶體洩漏。掌握這些記憶體管理技巧,能幫助我們在開發過程中避免常見的記憶體問題,確保應用的穩定性與效能。