18 实际工作中怎么做Jvm调优

vvEcho 2026-03-18 14:23:03
Categories: Tags:

1.确认问题

通过GC日志和监控工具来观察对应GC的一个频率,停顿时间,堆内存使用率这些指标;
定位是频繁的Minor GC还是Full GC, 还是单次停顿时间过长了

1
2
# G1 停顿目标示例
-XX:MaxGCPauseMillis=50 # 希望停顿 <50ms

2.调堆的大小

这是最直接的手段,年轻代太小会导致频繁的Minor GC,年老代太大会导致频繁的Full GC;
一般堆大小设置为存活对象大小的3到4倍,年轻代占堆的1/3 或1/2;

3.选GC算法

对延迟敏感的场景,G1或ZGC;对吞吐量敏感的场景,一般选择Parallel GC;

在线查看GC日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看进程 PID
jps -l

# 假设 PID=12345
# 动态开启 GC 日志
jcmd 12345 VM.log output=gc.log level=info tags=gc+age

# 停止 GC 日志
jcmd 12345 VM.log output=gc.log level=off

# 每 1 秒刷新一次
jstat -gc 12345 1000

# 启动录制JFR文件 指定录制5分钟
jcmd 12345 JFR.start name=gc_recording filename=/tmp/gc_recording.jfr settings=profile duration=5m

如果是GC的.log日志,一般会用jstat来查看
如果是GC的.jfr日志,一般会用Java Mission Control来查看

那如果突然OOM,怎么看对应时间点的GC日志呢?

1
2
3
4
#动态堆 dump
jcmd <pid> GC.heap_dump /tmp/heapdump_after_oom.hprof
#用jstat 查看当前堆占用和 GC 次数
jstat -gc <pid> 1000

总结
如果线上突发 OOM,而之前没有配置 GC 日志或 HeapDump,我会先确认 JVM 是否仍然存活;
如果进程还活着,我会用 jcmd GC.heap_dump 在线抓取堆 dump,结合 jstat -gc 查看 Minor / Full GC 次数、堆占用情况,分析老年代压力和对象晋升趋势;
如果进程已经崩掉,我会检查操作系统级 core dump 或 crash log,结合 jhsdb 分析对象分布;
即使事前没有日志,也可以事后定位 OOM 根因,并制定堆内存、对象创建或泄漏优化方案