Java 的記憶體管理包含記憶體分配(創建對象)與記憶體回收(GC),均由 JVM 自動完成。這降低了開發門檻,避免了 C/C++ 手動管理記憶體的風險。但也導致許多開發者忽視記憶體模型,寫出低效、佔用大的代碼。深入理解 GC,是進階高效 Java 開發的必修課。
以有向圖視角(頂點=對象/引用,有向邊=引用關係),從 GC Roots(如棧局部變量、靜態字段、JNI 引用)出發:
finalize() 尚未執行/執行中。若在 finalize() 中重新建立引用,可「復活」為可達。finalize() 執行完畢仍無引用。GC 真正回收記憶體。狀態轉換圖:
| 引用類型 | 創建方式 | 回收時機 | 典型場景 | |
|---|---|---|---|---|
| 強引用 | Object obj = new Object(); | 永不回收(寧願 OOM) | 普通對象持有 | |
| 軟引用 | SoftReference<T> ref = new SoftReference<>(obj); | 記憶體不足時回收 | 緩存(如圖片、網頁) | |
| 弱引用 | WeakReference<T> ref = new WeakReference<>(obj); | GC 掃描到即回收 | WeakHashMap、監聽器 | |
| 虛引用 | PhantomReference<T> ref = new PhantomReference<>(obj, queue); | 回收前入隊列,需配合 ReferenceQueue | 直接記憶體釋放、回收追蹤 |
| 收集器 | 新生代算法 | 老年代算法 | 特點 | 適用場景 |
|---|---|---|---|---|
| Serial | 複製 | 標記-壓縮 | 單線程,Client 模式默認 | 單核、小堆、嵌入式 |
| Parallel Scavenge | 並行複製 | 單線程標記-壓縮 | 吞吐優先,可自適應調節 | 批處理、科學計算、Server 默認(JDK 8) |
| Parallel Old | 並行複製 | 並行標記-壓縮 | 全並行,JDK 6+ | 多核、追求高吞吐 |
| CMS | 並行複製 | 並發標記-清除 | 低停頓,碎片整理需 Full GC | Web 應用、響應敏感系統 |
| G1 | Region 複製 | Region 標記-壓縮 | 分區、可預測停頓、混合回收 | 大堆(>4G)、JDK 9+ 默認 |
| ZGC / Shenandoah | 染色指針/讀屏障 | 並發壓縮/轉發 | 亞毫秒停頓,JDK 11/12+ 實驗/產品級 | 超大堆、極低延遲需求 |
String s = "abc";)。StringBuilder/StringBuffer。null、縮小作用域)。static 持有大對象/集合,延長生命週期。finalize(),改用 try-with-resources / Cleaner (JDK 9+)。SoftReference。Java GC 是一套精密的工程體系:分代假設奠定基礎,多種演算法權衡吞吐與停頓,收集器演進適應硬件變遷。作為開發者,理解對象生命週期、引用類型、分代結構、常見收集器特性,配合良好編碼習慣與 JVM 參數調優(-Xms, -Xmx, -XX:+UseG1GC 等),方能駕馭記憶體,構建高性能、穩定的 Java 應用。