JDBC4Connection中的hashmap不释放,导致OutOfMemory内存泄漏

背景:

每天跑批的一个分润任务出现了OutOfMemory内存泄漏,和小伙伴一起查找问题,一直也没有定位问题。

任务描述:

多线程操作一批数据,每批次10个线程,每个线程处理1W数据。处理大概5W左右会出现OutOfMemory内存泄漏。

定位问题:

一开以为有大量对象没有释放,所以手动进行释放处理。测试重跑任务,只是有一点点效果,问题依旧还在。

怀疑数据库配置问题,检查了mysql所有主从机器,没有发现配置异常。

最后找到运维大神导出当时dump日志。

获取dump日志:

halcon 深度学习分类内存占用率高 halcon内存无法释放_java

halcon 深度学习分类内存占用率高 halcon内存无法释放_java_02

ps:这里说一下运维大神的硬盘速度是真的快,几秒就传过来了。给了我一个log结尾的文件,我一开始还以为给错了。

解压文件,改文件后缀为.hprof文件格式。打开memory analyzer,open head dump。

halcon 深度学习分类内存占用率高 halcon内存无法释放_halcon 深度学习分类内存占用率高_03

halcon 深度学习分类内存占用率高 halcon内存无法释放_子线程_04

memory analyzer分析:

halcon 深度学习分类内存占用率高 halcon内存无法释放_SQL_05

halcon 深度学习分类内存占用率高 halcon内存无法释放_mysql_06

halcon 深度学习分类内存占用率高 halcon内存无法释放_SQL_07

halcon 深度学习分类内存占用率高 halcon内存无法释放_SQL_08

halcon 深度学习分类内存占用率高 halcon内存无法释放_halcon 深度学习分类内存占用率高_09

剖析问题:

看到有一堆JDBC4Connection,不知道什么东东。还特意看了一下我们之前关注的对象的内存占用。

从上面的图也能看出来每个子线程占用的内存情况。

halcon 深度学习分类内存占用率高 halcon内存无法释放_mysql_10

halcon 深度学习分类内存占用率高 halcon内存无法释放_SQL_11

halcon 深度学习分类内存占用率高 halcon内存无法释放_SQL_12

结合代码剖析问题:

JDBC4Connection里面有很多hashmap,应该是任务查询的数据。找到的执行查询的sql。对应到代码查看问题。

halcon 深度学习分类内存占用率高 halcon内存无法释放_SQL_13

halcon 深度学习分类内存占用率高 halcon内存无法释放_mysql_14

halcon 深度学习分类内存占用率高 halcon内存无法释放_java_15

halcon 深度学习分类内存占用率高 halcon内存无法释放_halcon 深度学习分类内存占用率高_16

halcon 深度学习分类内存占用率高 halcon内存无法释放_子线程_17

解决方案:

目前只是把先查询再删除改为直接删除。(此解决方案不可行)

最后的想法:

因为这个查询操作是在子线程里操作的。查询走的mysql从库,还有一个mysql主库在此日志同样有连接,但是没有这样的问题。目前怀疑的问题是:

  1. 子线程操作JDBC4Connection查询不释放
  2. 因为分表实现才用的是当当的sharding,怀疑是sharding的影响
  3. 怀疑mysql驱动bug问题影响

未完待续。。。

 

2021年03月30日20:16:32

这个问题好久之前就改好了,今天看到了帖子,结束一个帖子吧。

之前的解决方案不可以,直接删除使用shardingjdbc会导致数据库MySQL表死锁。

最终定位的问题是JDBC4Connection在同一主事物中缓存了所有操作的执行SQL脚本。应该属于之前猜测的第一种情况。

JDBC4Connection中有一个对象储存了SQL脚本。每个SQL脚本大约占用2KB。所有连接没有释放,缓存SQL脚本的对象越来越大,导致了oom。

SQL里写法是 字段 as 别名类型,500左右各字段,整个SQL脚本占用 2Kb左右字节。后期改为 select * ,之前基本查询了所有字段。每个子线程处理完,释放对象操作。最后从根本解决问题。