线上环境出了个问题:Young GC看起来很正常,但Full GC每天发生20多次,每次都让CPU飙得很高。你会怎么去排查和解决?
排查方向
检查Full GC触发原因
- 使用
jstat -gcutil <pid>
观察内存各区使用率,确认老年代是否在Full GC前接近占满 - 添加JVM参数
-XX:+PrintGCDetails -XX:+PrintGCDateStamps
获取详细GC日志 - 检查是否存在System.gc()调用导致人为触发
分析内存泄漏可能性
- 生成堆转储文件
jmap -dump:live,format=b,file=heap.hprof <pid>
- 使用MAT工具分析老年代对象分布,检查异常对象堆积
- 关注大对象分配日志
-XX:+PrintTenuringDistribution
检查GC策略配置
- 确认是否使用CMS或G1等低停顿收集器
- 检查新生代与老年代比例参数
-XX:NewRatio
- 验证晋升阈值
-XX:MaxTenuringThreshold
是否合理
常见解决方案
调整内存区域比例
# 增大新生代比例减少晋升
-XX:NewRatio=3
# 调整Survivor区占比
-XX:SurvivorRatio=8
优化GC策略参数
# CMS收集器配置示例
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
处理内存泄漏
- 修复代码中未关闭的资源连接
- 修改缓存策略避免无限增长
- 检查静态集合类是否持续添加元素
验证手段
监控指标对比
- 使用Prometheus+Grafana监控GC频率和耗时
- 对比调整前后CPU使用率曲线
- 观察应用TP99响应时间变化
压测验证
- 使用JMeter模拟峰值流量
- 对比Full GC次数是否显著下降
- 检查业务高峰期是否出现OOM