解决jvm内存溢出的方法

上一篇问题讲了怎么实现jvm内存溢出,现在已经实现了,那怎么去解决它呢.

 java.lang.OutOfMemoryError: GC overhead limit exceeded   

 简单来说,java.lang.OutOfMemoryError: GC overhead limit exceeded发生的原因是,当前已经没有可用内存,经过多次 GC 之后仍然没能有效释放内存。

众所周知,JVM 的 GC 过程会因为 STW.

STW: Stop-The-World: 是在垃圾回收算法执⾏过程当中,将JVM内存冻结丶应用程序停顿的⼀种状态

  • 在STW 状态下,JAVA的所有线程都是停⽌执⾏的 -> GC线程除外

只不过停顿短到不容易感知。当引起停顿时间的 98%都是在进行 GC,但是结果只能得到小于 2%的堆内存恢复时,就会抛出java.lang.OutOfMemoryError: GC overhead limit exceeded这个错误。Plumbr给出一个示意图:

 解决方法

1.给一个jvm参数 (不要用)

JVM 给出一个参数避免这个错误:-XX:-UseGCOverheadLimit

但是,这个参数并不是解决了内存不足的问题,只是将错误发生时间延后,并且替换成java.lang.OutOfMemoryError: Java heap space

2.增大jvm内存 (视情况而定)

还有一个偷懒的方法是:增大堆内存。既然堆内存少了,那就增加堆内存即可。

-Xms2048m -Xmx2048m

但是,这个方法也不是万能的。因为程序里可能有内存泄露。这个时候即使再增大堆内存,也会有用完的时候。

所以前两个方法都只是治标不治本而已。

3.从根本上找出占大内存的代码,优化它

其实还是有一个终极方法的,而且是治标治本的方法,就是找到占用内存大的地方,把代码优化了,就不会出现这个问题了。

怎么找到需要优化的代码呢?就是通过 heap dump 生产 jvm 快照,通过分析快照找到占用内存大的对象,从而找到代码位置。

通过设置-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump参数来生产快照,然后通过 VisualVM 或者MAT等工具分析快照内容进行定位。通过这个参数是将发生 OOM 时的堆内存所有信息写入快照文件,也就是说,如果此时堆内存中有敏感信息的话,那就可能造成信息泄漏了。

开始解决

可以用JDK1.8自带的jvisualvm工具分析,个人感觉不太好用

所以我选择用MAT工具

下载并安装MAT工具百度有,这里不做介绍

1.生成dump文件

在本地spring项目启动配置两个参数

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump

 然后用postman访问接口bbb/bbb01接口,死循环往userlist里面不停塞user对象.

 最终导致报内存溢出错误.

 停止这个服务.就会在项目的文件夹中自动生成一个heapdump文件.

 2.用MAT工具打开dump文件

 打开MAT,开始下面5个步骤.就打开了heapdump文件.

(注意,第一次下载mat后直接打不开heapdump文件,需要重启一下电脑才能打开heapdump文件)

3.认识下MAT工具的一点单词意思

shallow 浅的     retained 保留的     heap 堆     percentage  百分率      

dominator_tree   支配树(查看占大内存的类,以及类里面含的对象)    常用这个

histogram    柱形统计图(查看占大内存的对象)

shallow heap:对象本身的大小,如果是数组或集合则是各个元素的总大小。

retained heap:对象本身的大小 + 引用的其他对象的大小。

Shallow Size (对象自身占用的内存大小)

Retained Size (被GC后Heap上释放的内存大小)

with outgoing references(查看对象为什么消耗内存,查看对象引用的其他对象)

with incoming references(查看对象被谁引用)

 4.打开页面,点击dominator_tree

5.分析

发现了JVMneicunyichuController这个类占用内存非常大,然后点开发现原来是Arraylist里面有非常多的User对象

6.去代码中找

去代码中找JVMneicunyichuController这个类的ArrayList集合中为什么会有这么多User对象.

找到这个类的集合后发现原来是while死循环往集合里加User对象了.

7.修改优化代码

把这个死循环去掉,那么,这个内存溢出的问题就解决了.

帮助排查分析的两个界面:

方式一:点击Histogram,查看占大内存的对象.

 还有其他方式,可以自己百度了解.

猜你喜欢

转载自blog.csdn.net/weixin_70280523/article/details/131154974