dump文件分析OOM及线程堆栈

OutOfMemoryError (OOM)

如果项目报错: OutOfMemoryError: Java heap space,说明堆内存空间(Heap Space)中没有足够的空间来分配对象了。
一旦发生 OOM,系统有可能不可用,或者频繁重启。属于非常严重的问题。

OOM 的解决方法一:

比较简单粗暴的一种做法,是增大堆内存空间。
在 项目启动时,调大 -Xms 和 -Xmx 。
-Xms 参数用于设置JVM的初始堆内存大小,而-Xmx参数用于设置JVM的最大堆内存大小。

-Xms1024m  -Xmx2048m

OOM 的解决方法二:

-Xms 和 -Xmx 哪怕调大了,如果没有找到根本的原因,大对象不断创建,不断地占用堆内存空间,还是有可能会继续 OOM。

可以设置在发生 OOM 时自动 dump 文件,保存到指定的文件。
HeapDumpPath就是指定的文件路径,最好设置一下,免得OOM了找不到文件。
dump文件是进程的内存镜像,可以通过分析 dump 文件,找到导致 OOM 的代码。

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dumpfile/heapdump.hprof

oom 代码示例:

不断循环,不断创建对象,占用堆内存空间,模拟 OOM 的场景。

public class OomTest {

    public static void main(String[] args)  {
        createObject();
    }

    /**
     * 不断循环,不断创建对象,模拟 OOM 的场景
     *
     */
    public static void createObject()  {
        List<OomObject> oomList =new ArrayList<>();
        while (true) {
            OomObject oomObject = new OomObject();
            oomList.add(oomObject);
        }
    }

}

添加 jvm 相关启动参数( Vm option ) :

  • 点击 Edit Configurations:
    在这里插入图片描述

  • 点击 Modify options, 选择 Add Vm Options :

在这里插入图片描述

启动参数( Vm option ) 如下:

添加启动参数,设置最大内存为 8m,模拟 OOM 的场景。

HeapDumpOnOutOfMemoryError 表示在发生 OOM 时会自动 dump 。

-Xms4m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/heapdump.hprof

运行代码:

结果如下:

Connected to the target VM, address: '127.0.0.1:63909', transport: 'socket'
java.lang.OutOfMemoryError: Java heap space
Dumping heap to D:/heapdump.hprof ...
Heap dump file created [31923817 bytes in 0.263 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3210)
	at java.util.Arrays.copyOf(Arrays.java:3181)
	at java.util.ArrayList.grow(ArrayList.java:261)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
	at java.util.ArrayList.add(ArrayList.java:458)
	at com.example.demo.oom.OomTest.createObject(OomTest.java:21)
	at com.example.demo.oom.OomTest.main(OomTest.java:14)

可以看到 :

java.lang.OutOfMemoryError: Java heap space
Dumping heap to D:/heapdump.hprof ...

这里的 D:/heapdump.hprof ,就是 dump 文件保存的路径。

打开 dump 文件,分析大对象

点击 Profiler ,再点击 Open Snapshot ,选择 上面的 dump 文件 D:/heapdump.hprof 。

在这里插入图片描述

点击 Biggest Objects, 接着再点击 Calculate retained size and biggest objects.
可以看到 OomObject 这个对象占用了最大的内存。
生产环境的 dump 文件,一般都会很大,好几G 都有可能。要等多一会 。
结果如下:

在这里插入图片描述
Shallow 和 Retained 分别表示对象自身不包含引用的大小和对象自身并包含引用的大小。

在实际的情景中,往往会有多个对象及多个引用。
比如:在大对象中,对象A 占用的内存最大,
那么再看对象A中包含了哪些对象,比如 对象A包含了 A1,A2,A3,这里面A1占用的内存最大,
再看一下内存最大的 A1中包含了哪些对象,逐步深入。

如下图所示:
TaskThread 占用的内存最大,展开后发现 TaskThread 包含的内存最大,逐步深入,
就能找到导致oom的大对象。然后再搜索代码中的大对象。

在这里插入图片描述

使用 jdk 自带的 java visualvm ,分析dump文件, 找到 OOM 的代码

另外,也可以下载 MAT(Memory Analyzer Tool) 来分析 dump 文件。
此处使用 jdk 自带的 java visualvm 来分析 dump 文件, 找到 导致OOM 的代码 。

在 jdk 的 bin 文件中,找到 jvisualvm.exe 。点击即可运行。

在这里插入图片描述

  • 装入 hprof 后缀的 dump 文件 :

打开 VisualVM 后,点击左上角的图标 ,装入, 文件名选择 之前的 dump 文件 D:/heapdump.hprof 。

文件类型 选择 【堆Dump(*.hprof)】。

在这里插入图片描述

可以看到,在出现 OutOfMemoryError 异常错误时进行了堆转储,导致 OutOfMemoryError 异常错误的线程 是哪一个。

点击这个线程,即可显示导致OOM的线程堆栈。
生产环境的 dump 文件,一般都会很大,好几G 都有可能。要等多一会 。

在这里插入图片描述

  • 可以看到OOM的具体代码是类的哪一行:
    这个分析出来的代码,是OOM发生时的代码,并不一定是导致OOM的代码。
    最好结合上面分析出来的 大对象,一起排查。
    以占用过多内存的大对象为准。
    大对象占据过多的内存,就会导致某一次请求时OOM。

在这里插入图片描述

posted on   乐之者v  阅读(1355)  评论(0编辑  收藏  举报

努力加载评论中...

导航

点击右上角即可分享
微信分享提示