JVM堆内存溢出排查
一:堆内存溢出模拟
我们先来做一个堆溢出的测试
1: 改小堆内存的设置
-Xms20m -Xmx20m -XX:-UseGCOverheadLimit
2:写一段死循环的代码
public class HeapOOMTest {
public static void main(String[] args) {
List<OOMObject> userList = new ArrayList<>();
while (true){
OOMObject oomObject = new OOMObject();
oomObject.setBytes(new Byte[1]);
userList.add(oomObject);
}
}
}
@Data
public class OOMObject {
private Byte bytes[];
}
运行之后,如意得到了异常:java.lang.OutOfMemoryError: Java heap space
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.lixiucai.design.oom.HeapOOMTest.main(HeapOOMTest.java:17)
细心的小伙伴可能要问了,上面设置的-XX:-UseGCOverheadLimit 参数是干嘛的?这个是禁用GC overhead limt exceed检查,因为我们堆内存设置的特别小,运行的时候,总是会抛出java.lang.OutOfMemoryError: GC overhead limit exceeded,而不是我们期望的java.lang.OutOfMemoryError: Java heap space,所以我们把它禁用掉。
GC overhead limt exceed检查是Hotspot VM 1.6定义的一个策略,通过统计GC时间来预测是否要OOM了,提前抛出异常,防止OOM发生。Sun 官方对此的定义是:“并行/并发回收器在GC回收时间过长时会抛出OutOfMemroyError。过长的定义是,超过98%的时间用来做GC并且回收了不到2%的堆内存。用来避免内存过小造成应用不能正常工作。“
上面的程序很简单,我们通过代码检查,就会发现是死循环导致的,OOMObject这个对象始终无法被GC释放掉,然后从年轻代的区域,存活到老年代的区域,一直累加,突破了堆内存设定上限,然后OOM。但当代码很多的时候,我们不可能通过这种一行一行检查代码的方式来排查问题,若是有一种工具能还原OOM时,JVM的内存情况就好了,JVN提供了一个参数,使得在OOM的时候可以转储堆内存快照dump文件,然后我们可以使用JDK自带的工具Visual VM来查看分析dump文件。
二:堆内存dump文件生成与分析
1.JVM设置在OOM时生成dump文件
在JVM的参数里设置如下
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
第一个参数表示在OOM的时候生成dump文件,第二个参数设置生成的dump文件的路径
2.使用Visual VM来分析dump文件
Visual VM,自从 JDK 6 Update 7 以后已经作为 Oracle JDK 的一部分,位于 JDK 根目录的 bin 文件夹下,无需安装,直接运行即可。我们将服务器上生成的dump文件下载到本地,然后使用本地的Visual VM载入它。
点击 文件 –> 装入,然后选择文件类型为 堆Dump,点击打开
点击堆转储上的线程,可以查看线程日志,然后我们点击 类 页签,显示界面如下
列表是支 持排序的,我们按实例数或者大小做下倒序,就会发现堆内存里比较大的对象OOMObject排在最前面,然后就是我们要在代码里去找这些大对象出现的地方,排查代码的问题。
三:堆内存溢出的解决方案
1.代码的问题:
排查这些大对象出现的地方,是否有死循环,是否有没有做分页,做全表查询的代码等等。
2.堆内存确实设置的过小,改大它:
-Xms1024m -Xmx1024m
原文地址: https://blog.csdn.net/qq_33556185/article/details/121736740
本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
相关文章