接口 P99 从 90 毫秒涨到 3.1 秒,超时集中在每小时 00 分到 05 分,jstat -gc 里 FGCT 每分钟增加 3 秒,FGC 计数每小时多 12 次。碰到这种情况,我一般先确认改动有没有真的生效。

原因不复杂,整点跑的报表任务一次性把 60 万条明细读进 ArrayList,老年代瞬间占到 94%,触发连续 Full GC。任务结束后对象释放,下一小时重复一次。

「Full GC 停顿时间」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。别只看报错的最后一行,往上看几行,真正的起因通常在上面。

jstat -gc 21455 60000 30
jcmd 21455 GC.class_histogram | head -15
java -Xmx4g -Xlog:gc*:file=/tmp/gc.log:time,uptime -jar report.jar

同类问题如果隔一段时间又出现,多半是某个定时任务或重启流程把改动冲掉了。把这次用到的命令存进笔记,比记住结论有用,换个环境还能照着走。

具体做法是,把报表任务改成流式分页 每批 5000 条处理完就丢引用;限制任务并发 别和交易高峰重叠;用 jstat -gc 按分钟记录 FGC 和 FGCT 确认对齐整点;给任务单独一个堆或者拆到离线实例。

最后用这个标准收尾,整点前后 FGC 计数不再跳变 FGCT 每分钟增量低于 0.2 秒 接口 P99 回到 200 毫秒内。

作者 9823189