记录一次Java内存溢出排查过程

本文详细解析了一次Java程序中的内存溢出问题,通过分析内存映像文件,定位到问题根源在于一个局部变量ArrayList的过度使用,最终追溯到具体代码行,解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这两天公司的一个程序出现问题,频繁出现内存溢出错误OutOfMemory:GC overhead limit exceeded.

虽然知道这个错误的原因是因为Java虚拟机在频繁进行垃圾回收,使用了98%的时间进行垃圾回收,但是实际回收了不到2%的内存。但结合到代码中,还是无法知道为什么会出现这个问题。

程序的内存设置为3G,6G都不行,快的话10分钟就内存溢出。没有办法,只能给Java程序加上命令行

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\mat.bin

加上之后,如果程序再发生内存溢出,就会在指定位置生成内存映像文件(PS:如果等内存溢出之后,再去手动用jmap生成内存映像文件,可能那时的内存已经释放完了,导出来只有一点点)。

等了几天,程序照常内存溢出,成功生成了内存映像文件。

下载映像文件,使用memory Analyzer软件进行分析。

首先下载memory Analyzer,下载官网是https://www.eclipse.org/downloads/download.php?file=/mat/1.10.0/rcp/MemoryAnalyzer-1.10.0.20200225-win32.win32.x86_64.zip

下载页面可以选服务器,记得选国内的服务器。

下载后解压,记得修改MemoryAnalyzer.ini,把最大内存改大一点,不然都不够mat.bin内存映像文件用。

打开MemoryAnalyzer.exe,打开内存映像文件

打开后,可以看到,整个程序的大概内存情况,大概用了2.8G,鼠标放上去,显示其中单个类关联的大小就占了2.7个G

单击饼图,出现菜单,点击List objects -> with outging references

意思是查看这个类里面包含的对象

 

在这个页面中,点击第三列Retained Heap,让它从大到小排序

可以看到,其中的<Java Local> java.util.ArrayList@0x70c90de90这个变量占用了2.8个G左右

<Java Local>表示是局部变量,也就是线程栈帧中的变量,而不是类的成员变量。

也就是说明,这个ArrayList是在某个方法中生成的,这个方法是关联到AutoReForwardThread线程。

点开ArrayList,可以看到每个元素的类型是什么,还有总共有4万多个元素,元素的大小有96k

查看这些元素里面的值,大概知道对应的业务模块是什么,然后找到代码,看看是否有一个局部变量List,保存了这些对象

最后找到这里,这里从数据库中查询出数据,放到list中

最后验证了数据库,确实查出来几十万条数据,从而导致了Java内存溢出。

总结:List list局部变量在ClassA.method1()中定义,该方法在ThreadB中进行调用,那么list能关联到ThreadB,而关联不到ClassA。所以需要深刻理解Java中的成员变量和局部变量的存放位置,才能明白内存印象文件中类、变量、局部变量、线程中的关联关系。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值