使用mat分析内存溢出

文章描述了生产环境中频繁遇到内存溢出问题,通过MAT工具分析发现是由大对象未被回收,特别是com.mysql.cj.jdbc.result.ResultSetImpl对象占用大量内存。通过LeakSuspectReport找到根源并定位到特定线程和方法,解决了内存泄漏问题。

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

生产环境隔一段时间就会发生内存溢出,每次都是重启服务临时解决问题,这次使用mat分析了一下到底什么问题导致的内存溢出,从根本上解决一下这个问题,使用的工具就是mat(Memory Analyzer Tool)

发现问题:

服务器宕机,错误日志报错内存溢出,并且好多gc overhead limit exceeded

出现gc overhead limit exceeded,说明出现多次gc对象没有被回收掉的情况,猜想是有大对象没有被回收掉,下面就来验证一下

分析过程:

1.从生产上拿到dump文件,具体生成dump文件的过程这里不做解说

2.使用mat 打卡hprof文件

从整体情况可以看出,2.3 gb的堆内存,有大对象占用。

怀疑是有内存泄漏,我们通过Leak Suspect Report报告查看

3.点击下面按钮,选择Leak Suspect 查看报告

报告显示有4个问题:

显示org.springframework.boot.loader.LaunchedURLClassLoader 加载com.mysql.cj.jdbc.result.ResultSetImpl的时候占用了561M的空间(后面验证是查询数据库加载到内存的数据太多导致)

显示org.springframework.boot.loader.LaunchedURLClassLoader 加载com.mysql.cj.jdbc.result.ResultSetImpl的时候占用了561M的空间(后面验证是查询数据库加载到内存的数据太多导致)

显示http-nio-9010-exec-12这个线程持有本地变量多达555M

显示http-nio-9010-exec-19这个线程持有本地变量多达403M

以Leak Suspect 报告第一个问题为例,我们点开内存泄漏报告的Detail,查看其详情

Shortest Paths To the Accumulation Point视图显示如下

可以看出正是和org.springframework.boot.loader.LaunchedURLClassLoader

这个GC root相连导致当前Retained Heap占用相当大的Object对象无法被回收,而对象数量居然达到了360145个。

Accumulated Objects in Dominator Tree视图,可以看出Object对象中,到底是什么内嵌对象占用heap高。

可以看出,360145Object对象数组内部,主要是ByteArrayRow对象

我们继续向下看,通过按class类分组,来看看具体占用比例情况。

按class分组后ByteArrayRow对象占用了560M

右键点击 com.mysql.cj.jdbc.result.ResultSetImpl @ 0x6a0fe1a40,在弹出菜单中点击 Path To GC Roots → with all references

可以看到该对象到 GC Root 的各条路径:

一个对象可能有多条路径通往多个 GC Root。但一般来说,其中某一个 GC Root 必定是一个线程。从上图可以看到 com.mysql.cj.jdbc.result.ResultSetImpl 对象通往 GC Root 的路径有很多条,但最终都殊途同归到了线程对象 org.apache.tomcat.util.threads.TaskThread @ http-nio-9010-exec-12。这就是说,是 http-nio-9010-exec-12 线程在运行过程中创建出了 com.mysql.cj.jdbc.result.ResultSetImpl 对象。那么我们接着看看 http-nio-9010-exec-12 线程到底在干什么?

双击展开该线程的堆栈,接下来就要重点观察那些我们自己写的类里的方法,这里需要凭借一些对自己代码的熟悉度和经验了。我们可以看到堆栈中有调用到 SysApiServiceImpl.queryOrder方法,   打开可以看到里面的参数信息,policyNo和orderCode 的值为空,orderStatus值为00,01,03,10,20,30,40,50,60,61,62,63,D0,D1,D2,D3,D4,11,12,13,14,15,16,32,I0,I1,I2,I3,I4,11,12,13

 第二个问题和第一个问题是一类,第三个和第四个问题是一类问题

第三个问题定位基本和第一个问题步骤一样,只不过在内存泄漏报告的Detail页面,可以直接看到堆栈信息,定位到方法

总结,第三个和第四个问题不同的线程调用的方法一样,加载大量数据导内存中,导致了第二个问题和第一个问题

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值