调优效果通过三组量化差评估:GC频率(如Young GC从60次/分降至8次/分)、停顿时间(平均值110ms→42ms,P95 280ms→75ms)、回收效率(晋升量从15MB/次压至3MB/次)。

直接对比调优前后的 GC 日志,核心是抓三组可量化的“变化差”:GC 频率、停顿时间、内存回收效率。不是看单次日志像不像,而是统计趋势、算清比例、定位偏移点。
看频率变化:数清楚每分钟多少次 GC
重点关注 Young GC 和 Full GC 的单位时间发生次数:
- 用 jstat -gc [pid] 1000 60 或解析日志中的时间戳字段,统计 1 分钟内 Minor GC 次数;调优前若达 60 次/分,调优后降到 8 次/分,说明新生代配置或对象生命周期已改善
- Full GC 频次下降最有说服力:从“每 5 分钟 1 次”变成“连续 2 小时零 Full GC”,基本可判定老年代压力解除或泄漏修复
- 注意排除干扰:系统 gc() 调用(日志中含 System.gc())、监控探针强制触发等非自然 GC,需在对比时过滤
比停顿时间:盯住 P95 和平均值两个数字
单次停顿长短决定用户体验,但只看最大值容易误判,要结合分布:
- 提取每次 GC 后的 secs 值(如
0.150secs),计算 1 小时内所有 Young GC 的平均耗时和 P95 耗时;若平均值从 110ms → 42ms,P95 从 280ms → 75ms,说明 STW 显著收敛 - Full GC 停顿必须单独列项:从 4.2s → 1.3s 是质变;若仍 >1s,即使频次下降,也要检查是否仍有大对象晋升或元空间持续扩容
- G1 场景下关注 G1Evacuation Pause 的 young/mixed 类型耗时差异,mixed 若普遍超目标(如 -XX:MaxGCPauseMillis=200),说明 InitiatingHeapOccupancyPercent 设得太高
查回收效率:算回收量、晋升量、回收率
光看“释放了多少 MB”不够,要结合区域容量看健康度:
立即学习“Java免费学习笔记(深入)”;
- Young GC 回收率 = (GC 前 Eden 使用量 − GC 后 Eden 使用量) ÷ GC 前 Eden 使用量;调优后应稳定在 90%~98%,长期低于 85% 暗示 Survivor 太小或对象存活久
- 对比两次日志中 晋升量:例如 “123456K→12345K” 和 “234567K→134567K”,差值 ≈ 11MB 晋升;若调优前平均晋升 15MB/次,调优后压到 3MB/次,说明对象驻留年轻代能力增强
- Old 区使用量曲线是否“平缓下降”:调优前老年代每小时涨 500MB,调优后 6 小时仅升 80MB,配合 Full GC 消失,大概率已解决过早晋升或缓存未释放问题
辅以工具验证:别只靠肉眼扫日志
人工比对百条日志易漏关键波动,建议标准化处理:
- 用 GCViewer 分别导入调优前后 gc.log,它会自动统计吞吐量、平均停顿、GC 类型占比,生成对比柱状图,一眼看出 Mixed GC 比例是否降低
- 用 gceasy.io 在线分析,它能标出“内存泄漏嫌疑对象”“STW 异常峰值”,并给出优化建议打分,适合快速横向评估
- 写简单脚本提取关键字段(如 grep -o 'XXXK->YYYK' | awk -F'->' '{print $1,$2}'),导出 CSV 后用 Excel 做折线图,观察 Eden 回收后剩余量是否更稳定


















