一次频繁Full GC问题排查

频繁Full GC问题排查定位

先上结论:长时间运行MetricsClientHttpRequestInterceptor.servoMonitorCache.timerCache积累过多且不回收,导致频繁fullGc

起因:运维的同事说,你这个服务运行时间长了,内存不回收啊,内存一直往上加,我们半月就得重启一次,要不就返回503了,我心想不可能啊,java自带内存回收,后来一看系统监控果然,内存大趋势随着时间线性增长,很稳定,放大之后发现,内存是有回收的,只是每次的最低点都在提高,我第一反应是,对象到老年代了,一直在养老,钉子户越来越多导致的,那就铲除钉子户吧。

  1. jstat -gcutil [pid] 1000 查看gc执行频率,确实一直在Full GC ,而且还收不干净。

  2. jmap -F -dump:format=b,file=heapDump [pid] 先保留现场,不能让服务一直不可用,留好快照,让运维的同事先重启解决下。

  3. 用eclipse mat 工具打开dump文件,文件太大,3.13g,需要修改mat启动参数,如图:

    主要是这两行-Xmx4096m,-Xms1024m

  4. 点击Leak Suspects,查找内存泄漏

  5. 发现内存泄漏的class,

    • org.springframework.cloud.netflix.metrics.MetricsClientHttpRequestInterceptor
    • org.springframework.cloud.netflix.metrics.servo.ServoMonitorCache(servoMonitorCache)
    • java.util.HashMap(timerCache)

  6. 回到源码,查找对应class,发现

    Intercepts RestTemplate requests and records metrics about execution time and results.

    原来是为了统计执行时间和返回结果的,那就关掉吧。

  7. 在MetricsInterceptorConfiguration中

    1
    @ConditionalOnProperty(value = "spring.cloud.netflix.metrics.enabled", havingValue = "true", matchIfMissing = true)

    默认是true,需要在自己的配置文件中添加spring.cloud.netflix.metrics.enabled=false

  8. 发版本,上线,观察内存监控,很平稳。