博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
踩坑JVM溢出-----mybatis一二级缓存
阅读量:4107 次
发布时间:2019-05-25

本文共 2403 字,大约阅读时间需要 8 分钟。

根据需求开发了生产者消费者功能,生产者从Oracle数据库读取数据后,通过kafka发送给消费者,消费者从kafka中读取数据后,写入到mysql数据库中,功能需求就这样,比较简单,总量5000W数据,通过3个生产者读取写入到kafka中。

代码写完后经过简单的功能测试没问题,开始在测试环境上运行,大概运行了不到1小时发送了不到200万的数据时出现OOM   GC overhead limit exceeded,重复运行多次后确认存在问题,每次发送大概150W-200W数据时候出现OOM异常。

接下来在本地使用Jprofiler进行代码测试,发现运行一段时间后有大量的char[] 和String对象没有释放,如图:

而且size还在不断增大,这是导致OOM的直接原因,那么问题来了,是什么导致了这么多的char[] 和String对象呢?

首先排查代码,

String topic="testCsrk1";			String clientId="CsrkProducer0";		int begin=630681;//初始位置  630681    28000000		int end = 28000000;//结束位置70987838   204138956		int count=1 ;//循环控制条件		int posi=100;//一次循环数量		int id=begin;		OracleProducer producer=new OracleProducer(topic,false,clientId);		SqlSession sqlSession=factory.openSession(false);		OCsrkMapper oCsrkMapper = sqlSession.getMapper(OCsrkMapper.class);				int num=0;		while(count>0) {						Map
paramMap=new HashMap
(); paramMap.put("id", id); paramMap.put("posi", posi); paramMap.put("endid", id+posi); List
list=oCsrkMapper.selectCsrks(paramMap);//从数据库查询数据 int size=list.size(); num+=size; logger.info("*******此次条数 "+size); System.out.println("*******总计条数 "+num); if(id>=end) { //判断id是否超过发送的范围 System.out.println(" id is " +id); count=0; } if(size==0) { id=id+posi; } for(int i=0;i

没有使用char[]这种类型,代码中String对象也都是正常的,还得从其它方向上寻找问题。

这种类型的对象还有一种可能就是缓存,mybatis分为一级缓存和二级缓存。

一级缓存的作用域是SqlSession范围的,当在同一个sqlSession中执行两次相同的sql语句时,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。

需要注意的是,如果SqlSession执行了DML操作(增删改),并且提交到数据库,MyBatis则会清空SqlSession中的一级缓存,这样做的目的是为了保证缓存中存储的是最新的信息,避免出现脏读现象。
当一个SqlSession结束后该SqlSession中的一级缓存也就不存在了。

二级缓存的作用域是mapper的同一个namespace。不同的sqlSession两次执行相同的namespace下的sql语句,且向sql中传递的参数也相同,即最终执行相同的sql语句,则第一次执行完毕会将数据库中查询的数据写到缓存,第二次查询会从缓存中获取数据,不再去底层数据库查询,从而提高效率。也就是说二级缓存是跨SqlSession进行数据共享的

注意:一级缓存是不能被关闭的

好了,回到代码中sqlSession只被创建了一次,因此一级缓存被创建了后并未被清楚,加入以下清除一级缓存的代码进行修改

sqlSession.clearCache();			List
list=oCsrkMapper.selectCsrks(paramMap);//从数据库查询数据

重新使用Jprofiler进行测试,观察发现char[]和String对象的size仍然在增长,那代开mybatis的xml文件发现开启了二级缓存

那关闭对应sql的二级缓存

useCache="false"

重新使用Jprofiler执行,观察,发现char[]和String对象的size稳定在10M以下,连续运行超过2200万数据用时不到90分钟,内存使用量稳定在80M以下

 

后续的思考

1.如果xml中没有使用</cache>标签会不会不会出现这个问题

  在xml中去掉</cache>标签,同时去掉useCache="false"然后执行,观察char[]和String对象的size,会随着时间的增长而增长。

而在每次查询前加入sqlSession.clearCache();代码用来清除之前的一级缓存,观察观察char[]和String对象的size,很稳定,不会随着时间的增长而变化,说明清除一级缓存成功。

 

部分内容参考

 

 

 

你可能感兴趣的文章
8583协议深入理解 2
查看>>
STM32之中断与事件---中断与事件的区别
查看>>
STM32之CAN ---CAN ID过滤器分析
查看>>
PBOC/EMV之静态数据认证(SDA)与动态数据认证(DDA)
查看>>
BCD码
查看>>
Hash
查看>>
对称加密 和 非对称加密
查看>>
如何在 Notepad++ 開啟「分割視窗」同時檢視、比對兩份文件?
查看>>
Notepad++ 分割視窗的兩邊同時展示兩個不同文件的內容
查看>>
delphi Random()函数
查看>>
delphi 中 delete的用法
查看>>
MFC中char*,string和CString之间的转换
查看>>
COMMTIMEOUTS详解
查看>>
网络通信时字节序转换原理与网络字节序、大端和小端模式
查看>>
对SendMessage与PostMessage的理解
查看>>
用PostMessage或SendMessage发送结构体指针
查看>>
[VC]SendMessage和PostMessage发送消息(不同进程传递字符串)
查看>>
使用J-Link ARM烧录FLASH
查看>>
驻波比
查看>>
解FPGA中的RAM、ROM和CAM;ROM、RAM、DRAM、SRAM、FLASH
查看>>