JDBC4Connection中的hashmap不释放,导致OutOfMemory内存泄漏
背景:
每天跑批的一个分润任务出现了OutOfMemory内存泄漏,和小伙伴一起查找问题,一直也没有定位问题。
任务描述:
多线程操作一批数据,每批次10个线程,每个线程处理1W数据。处理大概5W左右会出现OutOfMemory内存泄漏。
定位问题:
一开以为有大量对象没有释放,所以手动进行释放处理。测试重跑任务,只是有一点点效果,问题依旧还在。
怀疑数据库配置问题,检查了mysql所有主从机器,没有发现配置异常。
最后找到运维大神导出当时dump日志。
获取dump日志:
ps:这里说一下运维大神的硬盘速度是真的快,几秒就传过来了。给了我一个log结尾的文件,我一开始还以为给错了。
解压文件,改文件后缀为.hprof文件格式。打开memory analyzer,open head dump。
memory analyzer分析:
剖析问题:
看到有一堆JDBC4Connection,不知道什么东东。还特意看了一下我们之前关注的对象的内存占用。
从上面的图也能看出来每个子线程占用的内存情况。
结合代码剖析问题:
JDBC4Connection里面有很多hashmap,应该是任务查询的数据。找到的执行查询的sql。对应到代码查看问题。
解决方案:
目前只是把先查询再删除改为直接删除。(此解决方案不可行)
最后的想法:
因为这个查询操作是在子线程里操作的。查询走的mysql从库,还有一个mysql主库在此日志同样有连接,但是没有这样的问题。目前怀疑的问题是:
- 子线程操作JDBC4Connection查询不释放
- 因为分表实现才用的是当当的sharding,怀疑是sharding的影响
- 怀疑mysql驱动bug问题影响
未完待续。。。
2021年03月30日20:16:32
这个问题好久之前就改好了,今天看到了帖子,结束一个帖子吧。
之前的解决方案不可以,直接删除使用shardingjdbc会导致数据库MySQL表死锁。
最终定位的问题是JDBC4Connection在同一主事物中缓存了所有操作的执行SQL脚本。应该属于之前猜测的第一种情况。
JDBC4Connection中有一个对象储存了SQL脚本。每个SQL脚本大约占用2KB。所有连接没有释放,缓存SQL脚本的对象越来越大,导致了oom。
SQL里写法是 字段 as 别名类型,500左右各字段,整个SQL脚本占用 2Kb左右字节。后期改为 select * ,之前基本查询了所有字段。每个子线程处理完,释放对象操作。最后从根本解决问题。