16G 堆跑 G1,老年代一直在 70% 以上,GC 日志里 Humongous 区域占 38%,每次 Mixed GC 要扫两百多个 Region,停顿 400 毫秒。碰到这种情况,我一般先确认改动有没有真的生效。

原因不复杂,超过 Region 一半大小的对象直接分配到 Humongous 区,跳过年轻代。Region 是 8MB 时 4MB 的数组就算大对象,批量导出正好每批建一个。

「G1 Humongous」相关的验证我通常做两遍,改完一次、隔天再看一次,确认不是临时生效。别只看报错的最后一行,往上看几行,真正的起因通常在上面。

java -XX:+UseG1GC -XX:G1HeapRegionSize=32m \
  -Xlog:gc+region=info:file=/tmp/gc-region.log -jar app.jar
grep -i humongous /tmp/gc-region.log | tail -5

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

改完隔一天再看一次,当场正常不代表能稳住。测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。

具体做法是,把 Region 调到 32MB 让 4MB 数组回到普通对象;导出改成分块处理 单块控制在 1MB 以内;用 -Xlog:gc+region=info 确认 Humongous 占比;观察 Mixed GC 的 Region 数和停顿。

最后用这个标准收尾,Humongous 占比降到 5% 以下 Mixed GC 停顿回到 100 毫秒以内。

作者 9823189