一、為什麼需要 JVM 調優?

默認 JVM 參數適用於小型應用,但在以下場景中往往表現不佳:

  • 高併發 Web 服務(如電商、支付系統)
  • 大數據處理(如 Spark、Flink 任務)
  • 實時性要求高的交易系統
  • 內存佔用大或 GC 停頓頻繁的應用

常見問題表現

  • 頻繁 Full GC,響應時間飆升
  • OutOfMemoryError 或 StackOverflowError
  • 系統吞吐量低,CPU 利用率異常
  • 應用啓動慢,預熱時間長

二、JVM 內存結構回顧(HotSpot)

調優前必須清楚內存佈局:

JVM 內存 = 堆(Heap) + 非堆(Non-Heap)

堆(線程共享):
├── 新生代(Young Gen)
│   ├── Eden
│   └── Survivor (S0, S1)
└── 老年代(Old Gen)

非堆:
├── 方法區(Metaspace,JDK 8+)
├── 棧(每個線程私有)
├── 程序計數器
└── 本地方法棧

💡 重點調優區域堆內存垃圾回收器(GC)

三、核心調優目標

目標

説明

降低 GC 頻率

減少 Stop-The-World(STW)停頓

縮短 GC 停頓時間

提升響應速度(尤其對延遲敏感系統)

提高吞吐量

單位時間內處理更多請求

避免內存溢出

合理分配內存,防止 OOM

四、關鍵 JVM 參數詳解

1. 堆內存設置

-Xms4g      # 初始堆大小(建議 = -Xmx,避免動態擴容)
-Xmx4g      # 最大堆大小

生產建議-Xms == -Xmx,防止運行時擴容導致性能抖動。

2. 新生代大小

-Xmn2g          # 設置新生代大小(推薦為堆的 1/3 ~ 1/2)
-XX:NewRatio=2  # 老年代:新生代 = 2:1(默認值,一般不需改)
-XX:SurvivorRatio=8  # Eden:S0:S1 = 8:1:1(默認)

📌 對象大多“朝生夕死”,適當增大新生代可減少 Minor GC 次數。

3. 垃圾回收器選擇(JDK 8 vs JDK 17+)

JDK 8 常用組合:

場景

推薦 GC

參數

吞吐優先(批處理)

Parallel GC(默認)

-XX:+UseParallelGC

延遲敏感(Web 服務)

CMS(已廢棄)

-XX:+UseConcMarkSweepGC

平衡型

G1(JDK 8u40+ 支持)

-XX:+UseG1GC

JDK 11+ 推薦:

GC

特點

適用場景

G1

可預測停頓、大堆友好

通用首選(4GB~幾十GB)

ZGC

停頓 < 10ms,支持 TB 級堆

超低延遲(JDK 11+ 實驗,JDK 15+ 生產可用)

Shenandoah

類似 ZGC,Red Hat 主導

低延遲替代方案

現代生產環境推薦(JDK 11+):

# G1 示例(平衡型)
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200   # 目標最大停頓時間(ms)
-XX:G1HeapRegionSize=16m   # 堆分區大小(可選)

# ZGC 示例(超低延遲)
-XX:+UseZGC
-Xmx16g

4. 元空間(Metaspace)調優(JDK 8+)

-XX:MetaspaceSize=256m       # 初始元空間大小
-XX:MaxMetaspaceSize=512m    # 最大元空間(防無限增長)

⚠️ 不設上限可能導致系統內存耗盡(尤其動態生成類的場景,如 Spring、Groovy)。

5. GC 日誌開啓(排查必備!)

# JDK 8
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:/path/to/gc.log

# JDK 9+
-Xlog:gc*:file=/path/to/gc.log:time,uptime,level,tags