首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 垃圾回收機制全面深度解析:演算法、收集器與調優實戰

     編輯:Java 程式設計入門

什麼是垃圾回收 (GC)

Java 堆儲存所有物件實例。物件由 new/newArray 等指令建立,無需手動釋放。GC 自動識別不再被引用的物件,回收記憶體並整理碎片,實現動態儲存管理。

GC 核心意義與權衡

優點缺點/挑戰
提高開發效率,消除記憶體洩漏、雙重釋放、懸空指標CPU/暫停時間開銷,影響應用回應性
保護程式完整性,為安全策略基石演算法不完美可能遺漏垃圾 (早期版本)
碎片整理提升分配效率調優複雜度高,需理解應用行為與收集器特性

物件存活判定:根節點追蹤 (Root Tracing)

GC Roots 包含:

  • 虛擬機棧區引用的物件 (區域變數表)
  • 方法區類靜態屬性引用的物件
  • 方法區常量引用的物件
  • 本地方法棧 JNI 引用的物件
  • 同步鎖持有的物件

從 GC Roots 出發向下搜尋,可達路徑上的物件為「存活」,不可達為「垃圾」。

四大經典 GC 演算法

分代收集理論與 HotSpot 實作

弱分代假說:多數物件朝生夕死、熬過越多 GC 越難死。HotSpot 劃分:

  • 新生代:Eden + S0 + S1 (預設 8:1:1),採複製演算法,Minor GC 頻繁、快。
  • 老年代:長期存活物件,採標記-整理,Major/Full GC 耗時長。
  • 元空間:類元資料 (JDK 8+),取代永久代,直接使用本地記憶體。

七大經典收集器組合

演算法原理優點缺點適用場景
引用計數
(Reference Counting)
每物件維護計數器,引用+1,失效-1,歸零即回收即時性、無長暫停、實時系統友善無法處理循環引用、計數器維護開銷大早期 Python、COM、Objective-C (ARC 編譯期處理)
標記-清除
(Mark-Sweep)
掃描標記存活,清除未標記解決循環引用、實作簡單產生記憶體碎片、需掃描全堆早期 JVM、CMS 初始標記階段
標記-整理
(Mark-Compact)
標記後將存活物件向一端移動,更新引用無碎片、分配指針碰撞快移動物件需更新引用、暫停較長老年代收集器 (Serial Old、Parallel Old)
複製
(Copying)
劃分 From/To 區,掃描存活物件複製到 To 區,角色互換無碎片、分配極快 (指針碰撞)、適合存活率低區域記憶體利用率 50%、存活率高時複製開銷大新生代 (Eden + Survivor)、Serial/Parallel Scavenge
收集器代演算法執行緒特色
Serial新/老複製/標記-整理單執行緒Client 模式預設、小記憶體、無併行
ParNew新複製多執行緒Serial 多執行緒版、配合 CMS
Parallel Scavenge新複製多執行緒吞吐量優先、自適應調節 (GC Ergonomics)
Serial Old老標記-整理單執行緒Serial 老年代、CMS 後備
Parallel Old老標記-整理多執行緒Parallel Scavenge 老年代、吞吐量優先
CMS老標記-清除併發低暫停、併發標記/清除、碎片整理需 Full GC
G1全堆標記-整理+複製多執行緒併發分區、可預測暫停、JDK 9+ 預設
ZGC全堆併發整理多執行緒併發亞毫秒暫停、彩色指針、負載閾值自適應、JDK 11+
Shenandoah全堆併發整理多執行緒併發併發搬移、Brooks 指針、JDK 12+

常用 JVM 參數與調優切入點

-Xms -Xmx          # 堆初始/最大值 (建議相等避免震盪)
-Xmn                # 新生代大小
-XX:SurvivorRatio   # Eden:Survivor 比例
-XX:+UseG1GC        # 啟用 G1
-XX:MaxGCPauseMillis=200  # G1 目標暫停
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xlog:gc*:file=gc.log  # GC 日誌
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./  # OOM 轉儲

調優三步走

  1. 監控:jstat -gcutil、VisualVM、Arthas、Prometheus+Grafana 觀察 GC 頻率、暫停、記憶體佔用趨勢。
  2. 分析:GC 日誌識別 Minor/Full GC 觸發原因 (分配速率、大物件直入老年代、動態年齡判定、System.gc()、元空間不足)。
  3. 調整:調大新生代降低 Minor GC、調整晋升年齡、切換收集器 (CMS→G1→ZGC)、啟用字串去重、檢查程式碼洩漏 (ThreadLocal、靜態集合、快取無淘汰)。

結語

GC 不是黑盒,而是基於成熟演算法與工程權衡的系統組件。理解分代假說、演算法優劣、收集器適用場景,結合業務特性 (延遲敏感 vs 吞吐優先) 選擇並調優收集器,是 Java 高階工程師的核心硬技能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved