1. 问题描述
在排查接口响应慢的过程中,通过prometheus监控系统看到JVM每隔一小时进行一次FullGC(非常准时),我们都知道FullGC是STW的,所以有必要进行深入排查。
2. 问题分析
- 每小时准时进行一次FullGC,我首先怀疑可能是应用本身有定时任务显式调用 System.gc() 进行主动FullGC,排查代码后没有发现主动调用System.gc(),查看gc.log后发现存在System.gc()调用,查看其他应用存在同样的问题,看来是个通用问题;
- jstack -l {pid} 查看应用进程的堆栈信息,发现有一个 RMI GC Daemon 和 RMI RenewClean 的 守护线程,应用是开启JMX的,所以会有这些进程;
- 通过进程堆栈信息,查看JDK源码(jdk1.8.0_242),发现 GC.java 中 Daemon 静态内部类有一个自旋进行 System.gc();DGCClient.java 中 sun.rmi.dgc.client.gcInterval 可以配置FullGC时间间隔默认3600秒。
结论:
由于应用开启了JMX对接监控系统,开启JMX后JDK默认会每小时进行一次 System.gc();
3. 解决方法
解决方法1:添加 -Dsun.rmi.dgc.client.gcInterval 属性并配置合理的值,默认是3600000毫秒(1小时),可以适当调大;
解决方法2:禁用RMI FullGC,添加-Dsun.rmi.dgc.client.gcInterval属性并将值设置为 Long.MAX_VALUE即 9223372036854775807;
解决方法3:禁止显示调用System.gc(),添加JVM选项 -XX:+DisableExplicitGC,不建议添加此JVM选项禁用显式调用.System.gc(),影响范围过大,且某些三方组件依赖System.gc()。