一句话总结
JVM 调优核心是在吞吐量和延迟之间做权衡。关键参数分四类:堆内存(-Xms/-Xmx/-Xmn,建议 Xms=Xmx 避免动态扩容)、GC 选择(吞吐优先用 Parallel,低延迟用 G1/ZGC)、GC 日志(-Xloggc 等,用于分析 GC 行为)、OOM 处理(-XX:+HeapDumpOnOutOfMemoryError 自动 dump)。调优流程:设目标 → 选 GC → 调堆大小 → 看日志 → 迭代优化。
初级理解
核心参数速查表
| 分类 | 参数 | 说明 | 示例 |
|---|---|---|---|
| 堆内存 | -Xms | 初始堆大小 | -Xms2g |
| -Xmx | 最大堆大小 | -Xmx4g | |
| -Xmn | 新生代大小 | -Xmn1g | |
| -XX:NewRatio | 老年代/新生代比例 | -XX:NewRatio=2(老:新=2:1) | |
| 元空间 | -XX:MetaspaceSize | 元空间初始大小 | -XX:MetaspaceSize=128m |
| -XX:MaxMetaspaceSize | 元空间最大大小 | -XX:MaxMetaspaceSize=256m | |
| -XX:MaxDirectMemorySize | 直接内存最大大小 | -XX:MaxDirectMemorySize=512m | |
| GC 选择 | -XX:+UseSerialGC | Serial + Serial Old | 客户端应用 |
| -XX:+UseParallelGC | Parallel Scavenge + Parallel Old | 吞吐量优先 | |
| -XX:+UseG1GC | G1 收集器 | 低延迟(JDK 9+ 默认) | |
| GC 日志 | -Xloggc | GC 日志路径 | -Xloggc:gc.log |
| -XX:+PrintGCDetails | 打印 GC 详情 | JDK 8 | |
| -XX:+PrintGCDateStamps | 打印 GC 时间戳 | JDK 8 | |
| OOM | -XX:+HeapDumpOnOutOfMemoryError | OOM 时自动 dump | 强烈建议开启 |
| -XX:HeapDumpPath | dump 文件路径 | -XX:HeapDumpPath=/logs/ |
中级深入
三种调优场景
| 场景 | 目标 | 推荐 GC | 关键参数 |
|---|---|---|---|
| 后台计算 | 吞吐量最大化 | Parallel | -XX:MaxGCPauseMillis、-XX:GCTimeRatio |
| Web 应用 | 低延迟,减少停顿 | G1 | -XX:MaxGCPauseMillis=200 |
| 大内存(>16GB) | 亚毫秒停顿 | ZGC | -XX:+UseZGC、-Xmx |
G1 专项调优
# G1 核心参数
-XX:+UseG1GC # 启用 G1
-XX:MaxGCPauseMillis=200 # 期望最大停顿时间(默认 200ms)
-XX:G1HeapRegionSize=4m # Region 大小(1~32MB,2 的幂)
-XX:InitiatingHeapOccupancyPercent=45 # 堆占用达到 45% 触发并发标记周期
-XX:G1ReservePercent=10 # 预留 10% 空间防止晋升失败
# G1 调优思路:
# 1. 先设 MaxGCPauseMillis,不要太小(如 50ms),否则频繁 GC
# 2. 观察 GC 日志,看实际停顿是否满足目标
# 3. 如果频繁 Full GC,增大堆或调低 IHOP
为什么建议 Xms = Xmx?
// Xms != Xmx 的问题:
// 1. 堆动态扩容时需要 Full GC 来整理空间,导致停顿
// 2. 扩容期间应用响应变慢
// 3. 内存抖动,GC 行为不稳定
// 建议:生产环境 Xms = Xmx,避免动态扩容
// 同时 -Xmn 也固定,避免新生代动态调整
高级拓展
JDK 8 vs JDK 11+ GC 日志
# JDK 8 GC 日志参数
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log
# JDK 11+ 统一日志(Unified Logging)
-Xlog:gc*=info:file=gc.log:time,level,tags
# gc*:所有 GC 相关日志
# info:日志级别
# file=gc.log:输出到文件
# time,level,tags:日志格式
# 常用 JDK 11+ GC 日志配置
-Xlog:gc+heap=debug:file=gc.log:time # GC + 堆变化
-Xlog:safepoint:file=safepoint.log # 安全点日志
调优流程
// ① 明确目标:吞吐量?延迟?内存占用?
// ② 选择 GC:根据目标选合适的收集器
// ③ 设置堆大小:根据应用内存需求设 Xms/Xmx
// ④ 设置新生代:根据对象生命周期调 -Xmn 或 NewRatio
// ⑤ 开启 GC 日志:观察 GC 频率和耗时
// ⑥ 迭代优化:根据日志调整参数,反复测试
// 调优不是一蹴而就,需要反复观察和调整
// 没有"万能参数",要根据实际场景定制
实战场景
典型 Web 应用 JVM 配置
# 4 核 8G 服务器,Spring Boot Web 应用
java -Xms2g -Xmx2g \
-Xmn1g \
-XX:MetaspaceSize=128m \
-XX:MaxMetaspaceSize=256m \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/logs/heapdump.hprof \
-Xlog:gc*=info:file=/logs/gc.log:time,level,tags \
-jar app.jar
GC 日志关键指标
# 关注以下指标:
# 1. Minor GC 频率:正常每分钟几次,如果每秒多次需要调大新生代
# 2. Minor GC 耗时:正常 < 50ms,如果 > 100ms 需要关注
# 3. Full GC 频率:正常几小时一次或没有,如果频繁需要排查
# 4. Full GC 耗时:正常 < 1s,如果 > 3s 需要优化
# 5. GC 后内存回收量:如果回收很少说明有内存泄漏
面试模拟
Q:常用的 JVM 调优参数有哪些?
A:堆内存:-Xms/-Xmx(建议相等)、-Xmn(新生代);元空间:-XX:MetaspaceSize/-XX:MaxMetaspaceSize;GC:-XX:+UseG1GC、-XX:MaxGCPauseMillis;日志:-Xloggc、-XX:+PrintGCDetails;OOM:-XX:+HeapDumpOnOutOfMemoryError。生产环境必须开启 GC 日志和 OOM dump。
Q:如何选择垃圾回收器?
A:客户端/小内存:Serial;后台计算/批处理:Parallel(吞吐量优先);Web 应用/低延迟:G1(JDK 9+ 默认);大堆/超低延迟:ZGC(JDK 11+)。没有银弹,要根据实际场景测试选择。
Q:为什么建议 Xms 和 Xmx 设置一样?
A:1) 避免堆动态扩容时的 Full GC 停顿;2) 扩容期间应用响应变慢;3) 内存大小稳定,GC 行为可预测。生产环境建议 Xms=Xmx,同时固定新生代大小。