悠悠楠杉
5种必知JVM调优实战场景(开发老鸟经验总结)
一、高并发下的Full GC噩梦
上周排查的电商秒杀系统案例:QPS冲到2万时出现每秒3次Full GC,页面响应直接飙到5秒以上。通过jstat -gcutil
观察到老年代10秒内爆满,但对象明明应该是短生命周期的。
解决方案:
1. 添加-XX:+HeapDumpOnOutOfMemoryError
获取内存快照
2. MAT分析发现是本地缓存未设置TTL
3. 关键参数调整:
bash
-XX:NewRatio=2
-XX:SurvivorRatio=8
-XX:MaxTenuringThreshold=15
经验:Young区过小会导致过早晋升,建议新生代占堆内存1/3到1/2
二、内存泄漏的隐蔽杀手
金融系统持续运行两周后OOM的经典案例。jmap -histo
发现HashMap.Entry数量异常增长,最终定位到是ThreadLocal未清理。
排查三板斧:
1. 定期执行jcmd <pid> GC.class_histogram
2. 添加-XX:NativeMemoryTracking=detail
3. 使用Arthas的memory
命令监控
java
// 错误示例
ThreadLocal
// 必须显式remove()
userHolder.remove();
三、CMS与G1的抉择时刻
物流系统每天凌晨定时卡顿15秒,原因是CMS并发模式失败。通过GC日志发现碎片率高达45%。
调优对比:
| 参数 | CMS方案 | G1方案 |
|--------------|----------------------|-----------------------|
| 回收器 | -XX:+UseConcMarkSweepGC | -XX:+UseG1GC |
| 停顿目标 | -XX:MaxGCPauseMillis=200 | -XX:MaxGCPauseMillis=100 |
| 内存配置 | -Xms4g -Xmx4g | -Xms8g -Xmx8g |
最终选用G1后,停顿时间控制在80ms以内。
四、MetaSpace的"幽灵"增长
某SpringBoot应用上线后MetaSpace持续增长,jconsole
显示加载类数量竟达5万+。原因是Hibernate动态生成类未释放。
关键配置:
bash
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
-XX:+TraceClassLoading
配合jcmd <pid> VM.classloader_stats
命令最终定位到是CGLIB缓存问题。
五、容器化环境的特殊挑战
K8s环境中某Pod频繁重启,原来是JVM未感知cgroup限制。典型症状是容器内存超限被OOMKilled。
必须配置:
bash
-XX:+UseContainerSupport
-XX:InitialRAMPercentage=70.0
-XX:MaxRAMPercentage=80.0
-XX:+UnlockExperimentalVMOptions
同时建议添加-XX:ActiveProcessorCount=4
避免CPU争抢。
调优工具箱推荐
- 诊断工具:Arthas + VisualVM + Prometheus
- 必备命令:
bash jstack -l <pid> > thread.txt jmap -dump:format=b,file=heap.bin <pid> jstat -gc <pid> 1000 10
- 参数模板:
bash -Xlog:gc*=debug:file=gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
黄金法则:调优前先收集至少24小时基线数据,没有监控的优化都是盲人摸象。