几天前,遇到了一个问题,从发现到解决,耗费了好几天,写一遍博客,记录下经过;
任务描述:将mysql存储的第三方数据,迁移到mongodb;
问题描述:数据迁移过程中,运行到大概1万多条的时候, 突然报java.lang.OutOfMemoryError: Java heap space
解决过程:因为第三方数据过大,通讯录记录可以达到几十兆,起初认为,新生成的大对象因为数据过大,无法保存于新生代中,只能保存在老年代中,而老年代的清除周期要比新生代周期长很多,所以内存的积累导致了最后的内存溢出(实际这个想法完全不合理,如果是可清除的内存,在内存不够的情况下,jvm会执行FullGC,不会出现内存溢出的情况)。
基于以上考量,就在for循环中手动加上System.gc(),可是仍然没有效果,然后在每隔一段时间,加上Thread.sleep(),仍然没有效果;
所以,基本可以确定,一定是有什么引用没有清除,导致了最后的内存溢出
此时使用万能的度娘搜索了一个插件,并安装
打开本地的命令窗口:jmap -dump:live,format=b,file=/opt/soft/heap_cms_1024.hprof 10628
备注:1、/opt/soft/ 该文件目录,如果没有,需要自建创建
3、heap_cms_1024.hprof是生成的文件名
2、10628是启动项目对应的进程号
执行以上命令会生产对应的文件
安装完插件后,左上角会有一个logo,如下图所示,点击后,打开内存分析窗口,点击左上角打开文件
点击文件后,点击对应的Leak Suspects
此时发现EntityManagerHolder已经占据了52.40%的内存,通过jpa的EntityManager 的对象进行相应查询
然后我在每次处理完10条数据后,就对EntityManager的对象调用一下clear(),问题,就解决了
然后在使用jdk的jvisualvm.exe 监控内存,发现内存已经很稳定了,ok