关于java:JVM结合MAT工具来分析OOM问题

49次阅读

共计 2456 个字符,预计需要花费 7 分钟才能阅读完成。

简略来演示一下 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 文件, 如果想要剖析内存泄露的话,就勾选红色框框。

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

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

进入 histogram 页面

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

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

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

第二,对象被谁援用

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

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

而后你能够看到哪些线程创立了过多的对象。

比方这里创立过多对象的线程就是 main thread

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

使得 main thread 占用这么多内存

点开一看,好家伙

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

持续开展

发现数组外面全是 Dandan 对象

说到这里,其实就水落石出了

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

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

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

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

thread_overview 的性能:展现出 JVM 的所有线程以及每个线程以及线程过后的办法调用栈,还有每个办法创立了哪些对象。

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

进入 thread_overview 界面

找到 main thread 线程,点开看看

你能够疾速看到 Demo4.java:11

这个时候,你还不是特地确定的。须要点开持续看看

能够看到这里确实创立了大量的 Dandan 对象。

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

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

简略总结一下

总结

咱们的方法论是:

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

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

下面这个是一个比较简单的 OOM 问题。只是一个 Demo, 目标是为了通知你如何应用 MAT 来剖析 OOM 问题。

如果简单一点的我的项目,在第三步中,如果出问题的代码是其余第三方中间件,比方 tomcat,jetty,rpc 等框架引起的 OOM,这个时候,还须要你对这些中间件比拟相熟能力定位问题。如果出问题的代码是业务代码,这个时候,是须要邀请负责该项目标开发工程师来进行定位代码的。

其实,大家齐全能够把 MAT 这个定位 OOM 问题的方法论,用到理论工作。

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

有问题,欢送留言。

正文完
 0