疑难杂症(一) MyBatis批量插入导致系统频繁FullGC

本文讲述了由于MyBatis批量插入大量数据导致的JVM频繁FullGC现象,分析了问题原因在于巨大的SQL语句和占位符对象消耗内存,进而影响系统性能。解决方案包括分批插入和提升服务器配置。

疑难杂症(一) MyBatis批量插入导致系统频繁FullGC

现象

服务运行一段时候,无法正常接收请求和响应消息。重启后系统正常运行。隔了几天后,再次出现系统假死,无法响应请求的情况。

排查

1.利用jstat命令查看gc情况在这里插入图片描述
​ JVM几乎每秒就要进行1到2次fullGC,这么夸张的GC频率,服务直接进入假死状态,无法正常运作。那么,是什么造成立这么频繁的fullGC呢?

2.jmap导出dump文件,利用jvisualvm进行进一步分析
在这里插入图片描述
​ 可以看到,char[]类型的实例占据了接近700M的内存,并且存在160多万个实例,而我们的服务器配置,是2核4G,分配给JVM的只有2G,年轻代和老年代各1G。

在这里插入图片描述
​ 查看具体的实例内容,按大小排序,排名前面几个是一个MySQL的insert语句,但是看它的大小,几乎个个都有100多M。而其中的100多万个实例中,类似以下图片中的实例占据了绝大部分。而这些,就是sql语句中的参数占位符。
在这里插入图片描述
​ 到了这一步,其实心里已经差不多对问题的原因有了一个差不多的猜测。估计就是因为程序执行了一个批量插入的操作,并且这个批量插入涉及的量实在太多了,估计有几十万的数量,结果出现了问题。

​ 根据sql语句的详细内容,我们很轻易就能定位到程序中的问题代码。具体代码涉及公司项目,就不同贴出来的。简单来说,就是使用了最常见的myBatis批量插入的实现方式,xml中的sql如下图所示。但是就是一次插入的数量实在太多,有十几,二十多万条。

  <insert id="batchSave" parameterType="java.util.List">
        insert into computer_box_calc_match (
        diskless_room_id,
        box_id,
        calc_id,
        version,
        add_time
        )
        values
        <foreach collection="list" item="item" index="index" separator="," >
            (#{item.disklessRoomId}, #{item.boxId}, #{item.calcId}, #{item.version}, #{item.addTime})
        </foreach>
    </insert>

​ 数量巨大的插入项,导致生成了巨大的sql语句以及数量众多的占位符对象。同时因为SQL过于巨大,MyBatis对SQL的解析也需要极长的时间,同时也占用了大量的CPU。这样就导致了其他请求的响应时间也变长,堆内存中的对象逐渐累积,导致了fullGC的发生,但fullGC在进一步抢占CPU的同时,又不能有效回收垃圾释放空间,导致频繁FullGC,系统彻底卡死。

解决方案

​ 1.对于批量的插入进行一定的拆分,将一次insert语句的插入数量控制在100左右,保证单次插入的时间较短,垃圾回收也能够顺利回收垃圾。

​ 2.对机器的配置做一个升级,内存加到8G,分配给JVM 6G,年轻代和老年代各占3G。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值