物件維護計數器,引用+1、釋放-1,歸零即回收。缺陷:無法解決循環引用。
MyObject obj1 = new MyObject();
MyObject obj2 = new MyObject();
obj1.ref = obj2;
obj2.ref = obj1;
obj1 = null; obj2 = null; // 計數器皆為 1,永不回收
Java 不採用此法(Python 採用)。
從 GC Roots 向下搜尋,無法到達的物件判定為不可達。GC Roots 包含:
不可達物件需經歷兩次標記才真正回收:
finalize():必要時執行最終化(不推薦使用)| 參考類型 | 強度 | 回收時機 | 典型用途 |
|---|---|---|---|
| 強引用 | 最強 | 永不回收(OOM 才回收) | 一般物件 Object obj = new Object() |
軟引用SoftReference |
次強 | 記憶體不足前回收 | 快取、圖片緩存 |
弱引用WeakReference |
較弱 | 下次 GC 必回收 | 快取、監聽器、ThreadLocal |
虛引用PhantomReference |
最弱 | 隨時回收,需配合 ReferenceQueue | 直接記憶體管理、堆外記憶體釋放 |
| 演算法 | 核心思想 | 優點 | 缺點 |
|---|---|---|---|
| 標記-清除 (Mark-Sweep) |
標記存活,清除其餘 | 實現簡單 | 效率低、產生大量記憶體碎片 |
| 複製 (Copying) |
劃分兩塊,存活者複製換邊 | 無碎片、分配快(指標碰撞) | 50% 空間浪費 |
| 標記-整理 (Mark-Compact) |
標記後向一端移動存活物件 | 無碎片、空間利用率高 | 需移動物件、更新引用,耗時 |
| 分代收集 (Generational) |
依物件年齡分區,分別用適合演算法 | 綜合效能最佳,主流 JVM 採用 | 實現複雜 |
GC 過程:Eden+S0 滿 → Minor GC → 存活者複製至 S1 → 清理 Eden+S0 → 角色互換。物件在 Survivor 熬過 MaxTenuringThreshold(預設 15)次 GC 晉升老年代。大物件(大陣列)直接進老年代。
| 收集器 | 類型 | 適用代 | 演算法 | 特點 |
|---|---|---|---|---|
| Serial | 單執行緒 | 新生代 | 複製 | 簡單高效,Client 模式預設,STW 暫停 |
| Serial Old | 單執行緒 | 老年代 | 標記-整理 | Serial 老年代版,備用方案 |
| ParNew | 多執行緒 | 新生代 | 複製 | Serial 多執行緒版,搭配 CMS |
| Parallel Scavenge | 多執行緒 | 新生代 | 複製 | 關注吞吐量,自適應調節 |
| Parallel Old | 多執行緒 | 老年代 | 標記-整理 | Parallel Scavenge 老年代版 |
| CMS (Concurrent Mark Sweep) |
並發 | 老年代 | 標記-清除 | 目標最短停頓,碎片問題,JDK 9 棄用 |
| G1 (Garbage First) |
並行+並發 | 全堆(分區) | 標記-整理+複製 | 面向服務端,可預測停頓,JDK 9+ 預設 |
-XX:PretenureSizeThreshold 設定閾值-XX:MaxTenuringThreshold 設定年齡閾值