重讀 James Gosling 的《Java 程式設計語言》後,整理了一些關於 Java 垃圾回收(Garbage Collection,GC)的筆記,這裡與大家分享核心觀念。
在 Java 中,物件透過 new 關鍵字建立於堆疊,但沒有對應的 delete 操作來手動釋放記憶體。當我們不再需要某個物件時,只需消除對它的引用,具體方式有三種:
null核心規則: 當程式碼無法再以任何路徑觸達某個物件時,該物件佔用的空間即符合回收資格。
GC 的最大優勢在於消除「懸空引用」問題。在允許手動管理記憶體的語言中,若物件被釋放後仍有引用指向它,便會產生 dangling reference。Java 的自動回收機制從根本上避免了這類錯誤。
finalize() 會在 GC 確定物件不可觸達、準備回收記憶體前被呼叫。重點如下:
finalize 中讓物件「復活」,後續再變不可觸達也不會再次觸發。finalize 的最佳實踐@Override
protected void finalize() throws Throwable {
try {
// 釋放自身持有的非記憶體資源
} finally {
super.finalize(); // 確保父類清理邏輯執行
}
}
注意:super.finalize() 建議放在 finally 區塊,保證執行。此外,物件被標記為垃圾時,它引用的其他物件可能已先被回收,狀態不可預期,因此 finalize 中不應依賴其他物件的狀態。
主要透過 Runtime.getRuntime() 或 System 類別:
gc():建議執行垃圾回收runFinalization():建議執行待處理的 finalize 方法freeMemory()、totalMemory()、maxMemory():記憶體資訊查詢System.gc() 與 System.runFinalization() 內部會委派給 Runtime 實例對應方法。
物件只有在「無任何引用指向」時才會被視為垃圾。但有時希望在仍有引用存在的情況下讓物件可被回收,這時需用到 java.lang.ref 套件下的引用物件。
| 層級 | 類別 | 特性 |
|---|---|---|
| 強可觸達 | 普通引用 | 預設狀態,絕不會被回收 |
| 軟可觸達 | SoftReference | 記憶體不足時才會回收;拋出 OutOfMemoryError 前保證已清除 |
| 弱可觸達 | WeakReference | 下一次 GC 即會回收,適合快取場景 |
| 虛可觸達 | PhantomReference | get() 永遠回傳 null;需配合 ReferenceQueue 追蹤物件終結,確保 finalize 已執行後再做清理 |
| 不可觸達 | 無引用鏈 | 可被直接回收 |
get():取得被引用物件(虛引用除外)clear():手動清除引用enqueue() / isEnqueued():佇列操作理解這四種引用強度,能讓我們在快取、資源管理等場景更精準地控制物件生命週期,充分發揮 GC 的彈性。