记一次生产系统每隔10小时(36000000毫秒)固定进行一次Full GC排查思路

一、 背景描述

某个应用在生产环境通过系统监控发现,应用每隔10小时就会触发一次Full GC,该系统当时承接的业务量并不大,而且固定10小时就会进行Full GC,通过监控时间轴发现Full GC频率很规律,直觉告诉我这不是JVM自身触发的Full GC操作,应该是某个定时任务中进行了垃圾回收操作,但是什么业务场景会存在这种情况呢?

二、问题排查

通过在测试环境上通过系统监控可以发现,应用的JVM使用情况并未达到Full GC条件,是系统调用了System.gc()方法产生的Full GC。于是,我在代码中对System.gc()方法调用进行了搜索,甚至为了防止是通过反射方式调用的,还检索了所有业务代码,但是均未发现有业务代码进行该方法的调用。

不过,在排查过程中,Jdk中有一个GC类却引起了我的注意:

在这里插入图片描述
在Java中Daemon一般用作标识守护线程,这里有一个Daemon类,是不是因为在这个线程类中调用System.gc()方法的原因呢?

查看sun.misc.GC.Daemon类的源码:

在这里插入图片描述

通过源码可以发现,Daemon类继承了Thread线程类,并且有调用System.gc()方法。

同时,在应用中,通过jstack命令查看,应用中确实有此线程运行:

在这里插入图片描述

通过对代码进行断点调试,发现Apache cxf相关类会有周期性Full GC的问题,我引入的相关依赖如下:

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
            <version>3.3.11</version>
        </dependency>

通过对源码解析发现,最终调用的情况如下:

  • org.apache.cxf.common.logging.LogUtils
    在这里插入图片描述
  • org.apache.cxf.common.logging.JDKBugHacks
    在这里插入图片描述
    注意这里:skipHack()方法的判断逻辑,通过这部分代码可以设置参数跳过执行创建守护线程的逻辑。
    在这里插入图片描述

三、原因分析

源码解析流程如下:LogUtils类加载时会通过静态代码块调用JDKBugHacks.doHacks()方法,此方法会获取系统环境变量org.apache.cxf.JDKBugHacks.gcRequestLatency,如果没有设置,默认为false,此时会通过反射调用sun.misc.GCrequestLatency方法,

在这里插入图片描述
初始化的时候deamon对象的值为null,此时会调用Daemon.create()方法,如下:

在这里插入图片描述
create() 方法中,会创建一个名字为 GC Daemon的守护线程,如下:

在这里插入图片描述

四、问题解决

Apache CXF是一个开源的Service框架,它实现了JCP和Web Servicez中的一些重要标准,大大简化了Web Service服务构建开发工作,通过上述对org.apache.cxf.common.logging.JDKBugHacks源码分析,可以在项目启动脚本中加入

-Dorg.apache.cxf.JDKBugHacks.gcRequestLatency=true

来跳过创建守护线程的逻辑,解决固定Full GC的逻辑。

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值