分享

【MyBatis】一次生产事故发现的一级缓存导致伪内存泄露问题

    “内存泄漏”指的是某些内存空间因为某些原因导致无法被正常回收,导致这部分空间始终无法再被利用。
    本次事故突发于上周末,具体表现为:CPU占用颇高,通过jstat命令查看进程发现FGC时间一直在增长。
    首先我根据掌握的线索初步定为原因是内存泄漏,但是具体原因未知,趁着客户还没爆炸赶紧将堆内存数据dump一份下来然后在本地分析:
1.png
2.png
3.png
4.png
    最终根据分析结果,定位问题出在Mybatis
    此时,我想到一个问题:myBatis是存在一级缓存和二级缓存的,这些是本地缓存,也就是直接常驻程序内存的
    因为线上服务器的堆内存分配策略是有一半多的分给了年轻代(程序会频繁大量产生短生命周期的对象),老年代的内存很少,也刚好就在4~6G之间,这么一看问题就很明了了,因为老年代内存不足的时候,就会触发GC,而且会直接导致FGC的产生。FGC会使得程序STW(Stop the world),CPU使用率飙升。
    根据相关资料查询所得:MyBatis的二级缓存默认关闭,一级缓存是无法完全关闭的,只能通过其他方案实现关闭的效果:
  1. mybatis:
  2.     configuration:
  3.         cache-enabled: false  #禁用二级缓存
  4.             local-cache-scope: statement  #一级缓存指定为statement级别</font>
复制代码
    将上述代码添加到application.properties或者nacos中,即可实现将一级缓存更改为statement级别,当statement关闭的时候相对应的缓存会被立即释放。
    上述方案可以避免因为一级缓存导致的内存泄露问题,但是也同样带来了额外的开销
    所以,个人认为ORM框架就做好ORM框架的事情,将缓存这种工作交给缓存中间件来做。
Felix
2024年7月29日 14:25
回复

使用道具 举报

没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则