一、JVM 調優核心思想
在深入具體方案之前,必須明確兩個核心思想:
- 調優的目的通常是為了解決以下問題:
- GC 停頓時間過長:應用出現卡頓。
- 吞吐量下降:單位時間內處理的請求變少。
- 內存溢出:發生 OutOfMemoryError。
- CPU 負載過高:頻繁的 GC 或線程競爭導致 CPU 資源緊張。
- 一切依賴於數據和場景:調優必須基於監控數據(GC 日誌、堆快照、性能分析工具),並根據應用類型(Web 服務、大數據計算、交易系統)來制定策略。
二、常用 JVM 調優參數
通常將參數分為堆內存、垃圾收集器、GC 日誌、其他性能相關幾大類。
2.1 基礎堆內存參數
# 設置初始堆大小
-Xms512m
# 設置最大堆大小
-Xmx2048m
# 設置年輕代大小
-Xmn512m
# 設置元空間大小(Java 8+)
-XX:MetaspaceSize=128m
-XX:MaxMetaspaceSize=256m
# 設置永久代大小(Java 7及之前)
-XX:PermSize=128m
-XX:MaxPermSize=256m
- -Xms 和 -Xmx
- 説明:設置堆的初始大小和最大大小。通常將它們設為相同的值,以避免在運行時動態調整堆大小帶來的性能波動。
- 示例:-Xms4g -Xmx4g (設置堆大小為 4GB)
- -Xmn
- 説明:設置年輕代的大小。整個堆 = 年輕代 + 老年代。增大年輕代會減小老年代。這個參數對 GC 性能影響很大。
- 示例:-Xmn2g (在 4G 堆中,年輕代佔 2G,老年代佔 2G)。通常設置為整個堆大小的 1/3 到 1/2。
- -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize
- 説明:設置元空間的初始大小和最大大小。在 Java 8 中,永久代被移除,由元空間取代。如果動態生成類較多(如 Spring 的 CGLib),需要限制其大小以防吃光所有內存。
- 示例:-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m
- -Xss
- 説明:設置每個線程棧的大小。如果系統有大量線程,過大的棧大小會佔用過多內存。過小則可能引起 StackOverflowError。
- 示例:-Xss256k (對於大多數 Web 應用,256k 足夠)
2.2 堆內存比例參數
# 新生代與老年代比例(默認約1:2)
-XX:NewRatio=2
# 設置年輕代中 Eden 和 Survivor 的比例
-XX:SurvivorRatio=8 # Eden:S0:S1 = 8:1:1
# 設置晉升老年代的年齡閾值
-XX:MaxTenuringThreshold=15
# 設置大對象直接進入老年代的閾值
-XX:PretenureSizeThreshold=1m
# 設置TLAB(線程本地分配緩衝區)大小
-XX:TLABSize=64k
2.3 垃圾收集器相關
選擇並優化合適的垃圾收集器是調優的核心。
- 並行收集器(吞吐量優先)
- 參數:-XX:+UseParallelGC / -XX:+UseParallelOldGC
- 説明:JDK 8 的默認收集器,關注高吞吐量。適合後台運算、大數據處理等不需要低延遲的場景。
- 示例:
# 使用Parallel GC
-XX:+UseParallelGC
# 設置並行GC線程數
-XX:ParallelGCThreads=4
# 設置最大GC暫停時間目標
-XX:MaxGCPauseMillis=100
# 設置吞吐量目標(GC時間與總時間比例)
-XX:GCTimeRatio=99
- CMS 收集器(低延遲)
- 參數:-XX:+UseConcMarkSweepGC
- 説明:以獲取最短停頓時間為目標,適用於 Web 服務、B/S 系統。在 JDK 14 中被移除。
- 示例:
# 使用CMS老年代收集器
-XX:+UseConcMarkSweepGC
# 使用ParNew新生代收集器
-XX:+UseParNewGC
# CMS後台線程數
-XX:ConcGCThreads=2
# CMS觸發百分比
-XX:CMSInitiatingOccupancyFraction=75
# 開啓CMS壓縮
-XX:+UseCMSCompactAtFullCollection
# CMS FullGC前進行壓縮
-XX:CMSFullGCsBeforeCompaction=0
- G1 收集器(推薦)
- 參數:-XX:+UseG1GC
- 説明:JDK 9 及以後的默認收集器,面向服務端、大內存、低延遲應用。它將堆劃分為多個 Region,並優先回收垃圾最多的 Region。
- 示例:
# 使用G1垃圾收集器
-XX:+UseG1GC
# 設置最大GC暫停時間目標
-XX:MaxGCPauseMillis=200
# 設置區域大小
-XX:G1HeapRegionSize=16m
# 設置併發GC線程數
-XX:ConcGCThreads=4
# 設置混合GC週期收集中最大舊區域數量
-XX:G1OldCSetRegionThresholdPercent=10
- ZGC 收集器(極致低延遲)
- 參數:-XX:+UseZGC
- 説明:新一代的低延遲垃圾收集器,目標是將停頓時間控制在 10ms 以下。適用於對延遲極其敏感的應用(如金融交易系統)。
- 示例:
# 啓用 ZGC
-XX:+UseZGC
# 調優參數
-XX:ZAllocationSpikeTolerance=2.0 # 分配峯值容忍度
-XX:ZCollectionInterval=300 # 強制GC間隔(秒)
-XX:ZFragmentationLimit=10 # 碎片化限制
-XX:ZProactive=true # 啓用主動GC
# 內存映射調優
-XX:ZUncommitDelay=300 # 內存未使用回收延遲(秒)
2.3 GC 日誌相關
沒有日誌,調優就是盲人摸象。必須開啓詳細的 GC 日誌。
- 詳細 GC 日誌(JDK 8 及之前)
# 開啓GC日誌
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
# 輸出GC日誌到文件
-Xloggc:/path/to/gc.log
# 開啓GC日誌輪轉
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=10M
- 統一日誌框架(JDK 9+ 推薦)
# 詳細 GC 日誌
-Xlog:gc*=debug:file=/app/logs/gc-%t.log:time,uptime,level,tags:filecount=10,filesize=100M
# 選擇性日誌(生產環境推薦)
-Xlog:gc=info:file=/app/logs/gc.log:time,uptimemillis,level,tags
-Xlog:gc+heap=debug
-Xlog:gc+ergo*=trace
-Xlog:gc+age*=debug
- 高級監控參數
# 打印命令行參數
-XX:+PrintCommandLineFlags
# 打印GC應用停頓時間
-XX:+PrintGCApplicationStoppedTime
# 打印GC前後堆信息
-XX:+PrintHeapAtGC
# 開啓類加載日誌
-XX:+TraceClassLoading
-XX:+TraceClassUnloading
# 在發生 OOM 時自動生成堆轉儲文件,用於事後分析
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/heapdump.hprof
2.4 JIT 編譯與性能優化
# 分層編譯(JDK 8 默認)
-XX:+TieredCompilation
# 編譯閾值調優
-XX:Tier0InvokeNotifyFreqLog=7
-XX:Tier2BackEdgeThreshold=100000
-XX:Tier3InvocationThreshold=2000
-XX:Tier3MinInvocationThreshold=100
# 代碼緩存大小
-XX:ReservedCodeCacheSize=512m
-XX:InitialCodeCacheSize=64m
# 方法內聯優化
-XX:MaxInlineSize=325
-XX:FreqInlineSize=325
-XX:InlineSmallCode=1000
三、不同場景的配置模板
3.1 開發環境配置
java -Xms512m -Xmx1g \
-Xmn256m \
-XX:MetaspaceSize=128m \
-XX:MaxMetaspaceSize=256m \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+PrintGC \
-XX:+PrintGCDateStamps \
-Xloggc:./logs/gc.log \
-jar app.jar
3.2 測試環境配置
java -Xms2g -Xmx4g \
-Xmn1g \
-XX:MetaspaceSize=256m \
-XX:MaxMetaspaceSize=512m \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=150 \
-XX:ParallelGCThreads=4 \
-XX:ConcGCThreads=2 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=./dumps/ \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-Xloggc:./logs/gc.log \
-jar app.jar
3.3 生產環境配置
java -Xms4g -Xmx8g \
-Xmn2g \
-XX:MetaspaceSize=512m \
-XX:MaxMetaspaceSize=1g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=100 \
-XX:ParallelGCThreads=8 \
-XX:ConcGCThreads=4 \
-XX:G1ReservePercent=15 \
-XX:InitiatingHeapOccupancyPercent=35 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/data/dumps/ \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-XX:+UseGCLogFileRotation \
-XX:NumberOfGCLogFiles=10 \
-XX:GCLogFileSize=10M \
-Xloggc:/data/logs/gc.log \
-jar app.jar
3.4 Docker容器配置
FROM openjdk:8-jre
# 設置JVM參數
ENV JAVA_OPTS="-Xms1g -Xmx2g -XX:+UseG1GC"
# 使用容器感知的JVM
ENV JAVA_TOOL_OPTIONS="-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap"
CMD java $JAVA_OPTS -jar app.jar
四、實戰調優示例
4.1 電商交易系統調優案例
場景特點:
- 高併發、低延遲要求
- 內存使用模式:中等對象分配率,長生命週期對象較多
- 峯值 QPS:10,000+
- 服務器配置:16核32G
調優方案:
#!/bin/bash
java -server \
# 堆內存設置
-Xms16g -Xmx16g \
-Xmn8g \
-XX:SurvivorRatio=8 \
-XX:MaxTenuringThreshold=10 \
# G1 收集器調優
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=100 \
-XX:InitiatingHeapOccupancyPercent=40 \
-XX:G1HeapRegionSize=16m \
-XX:G1ReservePercent=15 \
-XX:G1MixedGCCountTarget=16 \
# 元空間與棧
-XX:MetaspaceSize=512m \
-XX:MaxMetaspaceSize=512m \
-Xss512k \
# 性能優化
-XX:+TieredCompilation \
-XX:ReservedCodeCacheSize=512m \
-XX:+UseStringDeduplication \
# 監控與診斷
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/app/logs/heapdump.hprof \
-Xlog:gc=info:file=/app/logs/gc.log:time,uptime,level,tags:filecount=10,filesize=100M \
-XX:ErrorFile=/app/logs/hs_err_pid%p.log \
# 應用JAR
-jar ecommerce-app.jar
4.2 大數據處理應用調優
場景特點:
- 高吞吐量要求,延遲不敏感
- 大內存使用,頻繁創建臨時對象
- 批量數據處理
調優方案:
#!/bin/bash
java -server \
# 大堆內存設置
-Xms32g -Xmx32g \
-Xmn24g \
-XX:SurvivorRatio=6 \
# 並行收集器(吞吐量優先)
-XX:+UseParallelGC \
-XX:+UseParallelOldGC \
-XX:ParallelGCThreads=16 \
-XX:GCTimeRatio=99 \
-XX:MaxGCPauseMillis=500 \
# 大對象處理
-XX:PretenureSizeThreshold=2m \
-XX:+AlwaysPreTouch \
# 性能優化
-XX:+UseLargePages \
-XX:LargePageSizeInBytes=2m \
-XX:+UseCompressedOops \
-XX:+UseCompressedClassPointers \
# 監控配置
-Xlog:gc*=info:file=/app/logs/gc.log:time,uptime,level,tags \
-XX:NativeMemoryTracking=detail \
-jar data-processing-app.jar
五、監控與診斷工具實戰
5.1 命令行工具使用示例
# 1. 實時監控 GC 情況
jstat -gc <pid> 1s
# 2. 查看堆內存摘要
jmap -heap <pid>
# 3. 生成堆轉儲
jmap -dump:live,format=b,file=heap.hprof <pid>
# 4. 查看類加載統計
jstat -class <pid> 1s
# 5. 線程分析
jstack <pid> > thread_dump.txt
# 6. 原生內存跟蹤
jcmd <pid> VM.native_memory summary
# 7. 全面的診斷信息
jcmd <pid> PerfCounter.print
5.2 自動化監控腳本
#!/bin/bash
# monitor_jvm.sh
PID=$1
LOG_DIR="/app/monitor"
INTERVAL=30
while true; do
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# GC 統計
jstat -gc $PID > $LOG_DIR/gc_$TIMESTAMP.log 2>&1
# 線程轉儲(每5分鐘一次)
if [ $(($(date +%s) % 300)) -eq 0 ]; then
jstack $PID > $LOG_DIR/thread_dump_$TIMESTAMP.log 2>&1
fi
# 內存使用
ps -p $PID -o pid,ppid,pmem,pcpu,rsz,vsz,comm >> $LOG_DIR/memory_$TIMESTAMP.log 2>&1
sleep $INTERVAL
done
本文章為轉載內容,我們尊重原作者對文章享有的著作權。如有內容錯誤或侵權問題,歡迎原作者聯繫我們進行內容更正或刪除文章。