名字想费脑的坤宝
发布于 2026-10-12 / 8 阅读
1
0

一次线上 Full GC 的排查记录

背景

中秋前的周五晚上,订单服务开始出现间歇性超时,监控上 RT 从 80ms 涨到 1.2s,同时观察到 Full GC 频率从每天两次变成每十分钟一次。这篇文章记录完整的排查过程。

第一步:先看 GC 日志

jstat -gcutil $(pgrep -f order-service) 1000 20

Old 区使用率在 92% 上下反复横跳,每次 Full GC 只能回收 3% 左右,典型的"回收不动"。

第二步:dump 堆

jmap -dump:live,format=b,file=/tmp/heap.hprof $(pgrep -f order-service)

用 MAT 打开后,Dominator Tree 第一位是一个 1.8G 的 ConcurrentHashMap,占整个堆的 70%。

第三步:找到谁在往里写

顺着引用链找到业务代码里的本地缓存:key 是「用户 ID + 日期」,但过期清理任务因为一次重构被删掉了。每天新增约 40 万条,跑了两周就撑爆了老年代。

结论

  1. 本地缓存必须有过期策略,最好用带容量上限的实现(Caffeine)。
  2. JVM 参数里加 -XX:+HeapDumpOnOutOfMemoryError,出事时能省很多时间。
  3. 给堆加个容量告警,别等 Full GC 找上门。

这次问题本身不复杂,难的是从「接口慢」推导到「缓存没清」,中间花了大半天。


评论