美文网首页
JVM-结合MAT工具来分析OOM问题

JVM-结合MAT工具来分析OOM问题

作者: 别拿爱情当饭吃 | 来源:发表于2021-04-23 12:05 被阅读0次

    简单来演示一下OOM的分析和实战。

    直接上代码:

    public class Demo4 {
    
        public static void main(String[] args) {
            List<Dandan> list = new ArrayList<>();
            while (true){
                list.add(new Dandan());
            }
        }
    }
    
    class Dandan{
    
    }
    
    

    JVM参数:

    -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -Xms10m -Xmx10m -XX:+PrintGCDetails -Xloggc:gc_dandan.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./

    运行后的日志:

    java.lang.OutOfMemoryError: Java heap space
    Dumping heap to ./java_pid22788.hprof ...
    Heap dump file created [13244840 bytes in 0.050 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:267)
        at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:241)
        at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:233)
        at java.util.ArrayList.add(ArrayList.java:464)
        at com.hailintang.demo.jdk8.gc.oom.Demo4.main(Demo4.java:11)
    
    Process finished with exit code 1
    

    java.lang.OutOfMemoryError: Java heap space

    首先,这里明确告诉我们内存泄露的地方是:堆

    因为配置了参数:-XX:+HeapDumpOnOutOfMemoryError

    会在程序发生OOM的时候,自动生成一个文件:java_pid22788.hprof

    命名格式为:java_pid(程序的进程号).hprof

    接下来当然是用MAT来分析:hprof文件

    在分析之前,我们重点关注什么?

    • 第一,哪些对象占用大量内存。
    • 第二,对象被谁引用。(就是要知道为什么它无法释放的意思)
    • 第三,定位到具体哪行代码,进行分析问题

    打开hprof文件,如果想要分析内存泄露的话,就勾选红色框框。

    image

    这里,我们首先看看那些对象占用大量内存。按红色框框Histogram按钮

    image

    第一,哪些对象占用大量内存

    进入histogram页面

    image

    进来页面后,你一眼就能发现哪个对象占用的内存最多。

    比如这里就是明显的class com.hailintang.demo.jdk8.gc.oom.Dandan这个类占用了过多内存。

    这里说了,这个Dandan类的对象有360146个。到目前为止,我们暂时确定了Dandan对象占用了大量内存。

    第二,对象被谁引用

    接下来,我们看看内存过多的对象是被谁引用。

    那这个时候需要用到MAT的dominator-tree:就是用来分析对象之间的关系的工具。

    image

    然后你可以看到哪些线程创建了过多的对象。

    比如这里创建过多对象的线程就是main thread

    image

    然后你展开这个main thread看看到底创建了什么对象

    使得main thread占用这么多内存

    image

    点开一看,好家伙

    发现是一个java.lang.Object[]数组。

    继续展开

    发现数组里面全是Dandan对象

    说到这里,其实就真相大白了

    经过层层展开。main thread线程创建的对象和在histogram界面中占用过多内存的对象Dandan对上了。

    第三,定位到具体哪行代码,进行分析问题

    找到引用后,最后一步就是要定位一下具体是哪行代码创建了这么多对象?

    这个时候需要另一个视图thread_overview。红圈所示

    thread_overview的功能:展示出JVM的所有线程以及每个线程以及线程当时的方法调用栈,还有每个方法创建了哪些对象。

    特别说明一下:栈,后进先出,所以,看图的时候,从下往上看

    image

    进入thread_overview界面

    image

    找到main thread线程,点开看看

    image

    你可以快速看到Demo4.java:11

    这个时候,你还不是特别确定的。需要点开继续看看


    image

    可以看到这里的确创建了大量的Dandan对象。

    到这里你再结合一下大头菜的代码:

    image

    好了,到这里,基本上已经找到了具体是哪行代码引起的OOM问题。

    简单总结一下

    总结

    我们的方法论是:

    • 第一,哪些对象占用大量内存。------对应的MAT的histogram
    • 第二,对象被谁引用。(就是要知道为什么它无法释放的意思)------对应MAT的dominator-tree
    • 第三,定位到具体哪行代码,进行分析问题----对应MAT的Thread-overview

    然后,我们根据方法论,结合MAT工具,一个一个步骤来进行排查。目的是为了找到具体哪行代码引起的OOM问题。

    上面这个是一个比较简单的OOM问题。只是一个Demo,目的是为了告诉你如何使用MAT来分析OOM问题。

    如果复杂一点的项目,在第三步中,如果出问题的代码是其他第三方中间件,比如tomcat,jetty,rpc等框架引起的OOM,这个时候,还需要你对这些中间件比较熟悉才能定位问题。如果出问题的代码是业务代码,这个时候,是需要邀请负责该项目的开发工程师来进行定位代码的。

    其实,大家完全可以把MAT这个定位OOM问题的方法论,用到实际工作。

    好了,今天的技术分享就到这里。

    有问题,欢迎留言。

    相关文章

      网友评论

          本文标题:JVM-结合MAT工具来分析OOM问题

          本文链接:https://www.haomeiwen.com/subject/zcjcrltx.html