引言
想象一下,Java 程序運行就像在一個巨大的圖書館里借書還書。這個圖書館(JVM 的內存堆區)為了高效運轉,需要一個聰明的“圖書管理員”來清理失效的書籍(垃圾對象)。這,就是垃圾回收器(GC)的使命!
一、什么是 GC?
GC(Garbage Collection)是 JVM 自動內存管理的重要組成部分,負責回收不再被引用的對象所占用的內存空間,防止內存泄露和內存溢出。
1.1 為什么需要 GC?
- 自動內存管理,減輕開發者負擔
- 避免野指針、內存泄露等問題
- 保證 Java 應用穩定高效運行
1.2 GC 面臨的挑戰
- 如何在不打斷業務的前提下進行垃圾回收?
- 如何避免過多的 STW(Stop-The-World)?
- 如何在高并發、大內存場景下依然穩定?
二、JVM 內存結構簡析(理解 GC 的基礎)
JVM 堆區被劃分為以下幾個區域:
- 新生代(Young Generation):包括 Eden 和兩個 Survivor 區
- 老年代(Old Generation):存放長生命周期的對象
- 元空間(Metaspace):替代原有的永久代,存放類的元數據
垃圾回收的重點主要在 新生代和老年代。
三、GC 算法簡述
Java GC 的核心算法主要有:
- 復制算法(Copying):用于新生代
- 標記-清除(Mark-Sweep):用于老年代
- 標記-壓縮(Mark-Compact):避免內存碎片
- 分代收集理論:新生代頻繁回收,老年代少回收
四、GC 發展史:從 Serial 到 ZGC
4.1 Serial GC(串行垃圾回收器)
- 回收機制:新生代使用復制算法,老年代使用標記-壓縮算法
- 回收線程:單線程
- 觸發機制:內存耗盡或觸發 Full GC 時
缺點
- 每次 GC 都會 Stop-The-World,且只能使用單線程
示例
-XX:+UseSerialGC
📌 適用場景:嵌入式、小型應用、單核處理器
4.2 CMS GC(Concurrent Mark Sweep)
CMS 是第一個低延遲為目標的 GC,著眼于縮短老年代的 GC 停頓時間。
工作流程
初始標記(STW) → 并發標記 → 重新標記(STW) → 并發清除
特點
- 多線程并發標記和清除,減少 STW
- 使用 標記-清除 算法,導致內存碎片問題
示例參數
-XX:+UseConcMarkSweepGC
缺點
- 并發失敗風險:老年代空間不足時需退化為 Serial Old GC
- 空間碎片影響分配性能
📌 適用場景:中大型系統,對響應時間敏感的 Web 應用
4.3 G1 GC(Garbage First)
G1 GC 是 JDK 9 之后的默認 GC,旨在取代 CMS。
原理
- 將整個堆劃分為多個大小一致的 Region(既可作為 Eden、Survivor、Old)
- 基于 Region 的優先級回收策略:優先回收垃圾最多的 Region
- 并發標記后,通過 Evacuation 將存活對象復制到新的 Region,實現壓縮
回收流程
初始標記(STW) → 并發標記 → 最終標記(STW) → 篩選回收(STW)
特點
- 支持大堆(數十 GB)
- 可配置 Pause Time(停頓目標)
- 減少 Full GC 的頻率
示例參數
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
📌 適用場景:中大型服務端應用,追求吞吐和響應時間平衡
4.4 ZGC(Z Garbage Collector)
ZGC 是一個為低延遲場景設計的 GC,目標是將所有 GC 停頓控制在 10ms 以內。
特點
- 幾乎全程并發執行,所有 GC 階段都不長時間阻塞應用線程
- 使用 染色指針(Colored Pointers) 來標識對象狀態
- 通過讀屏障和寫屏障實現引用更新的同步
技術亮點
- 支持極大的堆內存(最高可達 TB 級)
- 多階段并發整理,移動對象時應用線程無需停止
示例參數
-XX:+UseZGC
-XX:+UnlockExperimentalVMOptions
📌 適用場景:金融、電商、游戲等低延遲業務
五、不同 GC 的對比總結
特性 | Serial | CMS | G1 | ZGC |
---|---|---|---|---|
停頓時間 | 高 | 中 | 低 | 極低 |
并發回收 | 否 | 是 | 是 | 是 |
內存碎片 | 無 | 有 | 無 | 無 |
吞吐量 | 高 | 中 | 高 | 中 |
響應時間 | 差 | 好 | 更好 | 極佳 |
大內存支持 | 差 | 一般 | 好 | 極好 |
是否壓縮整理 | 是 | 否 | 是 | 是 |
六、GC 日志分析建議
可以通過以下 JVM 參數輸出 GC 日志:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log
常見指標:
GC time
:單次回收的耗時freed memory
:回收掉的內存大小pause time
:STW 的具體時間
七、真實案例分析
場景:大數據系統使用 CMS 導致頻繁 Full GC
問題: CMS 回收速度跟不上對象創建速度,頻繁觸發 Full GC,導致延遲劇增。
解決方案: 切換為 G1 GC,并設置合理的 MaxGCPauseMillis
,顯著降低了延遲峰值。
八、選擇建議
應用場景 | 推薦 GC |
---|---|
單線程、小型程序 | Serial |
中等延遲要求 | CMS |
大型服務端系統 | G1 |
超大堆、極低延遲 | ZGC / Shenandoah |
九、總結與未來展望
JVM 垃圾回收技術不斷進化,從最初的串行單線程到如今幾乎無感知的并發收集器,反映了 Java 在現代應用場景下對性能、可伸縮性和穩定性的持續追求。
未來,ZGC 與 Shenandoah 的持續優化將成為主流趨勢,也許某一天,GC 將真正做到“零成本”!
🔚 尾聲
👍 點贊 + ? 收藏,助你 GC 不迷路!
📬 評論聊聊你在使用 GC 中踩過的坑,或者你的調優秘籍~
📌 關注我,帶你一起玩轉 Java 性能調優!