应用延迟尖峰与 GC 同时出现,并不意味着“把堆调大”就能解决。停顿可能来自高分配速率、老年代回收、元空间增长或容器内存边界不合理。
收集低风险证据
jcmd $PID VM.flags
jcmd $PID GC.heap_info
jstat -gcutil $PID 1000 20
jcmd $PID VM.native_memory summary
生产环境应优先分析已启用的 GC 日志。jmap -dump 可能造成长暂停和大量磁盘写入,必须经过容量和影响评估。
阅读 GC 事件
-Xlog:gc*,safepoint:file=/var/log/app/gc.log:time,uptime,level,tags
关注暂停原因、回收前后占用、事件频率和晋升失败。堆在 Full GC 后仍持续抬升才更像存活对象泄漏;高频 Young GC 则常与分配速率和对象生命周期有关。
调优顺序
- 先确认容器 limit 与 JVM 最大内存、堆外内存的关系
- 用 JFR 或 profiler 找到分配热点和锁等待
- 根据延迟目标选择 G1、ZGC 等收集器,而非照搬参数
- 每次只改变少量参数并保留对照数据
收尾清单
用同一业务负载比较吞吐、P99、GC 时间占比和 RSS。将 GC 日志纳入集中采集,但避免把对象明细等敏感信息长期保留。