当我们的java程序遇到频繁full gc或者oom的时候,我们常常需要将当前的heap dump出来进行进一步的分析。MAT是用于分析heap dump的神器。

1 生成heap dump

heap dump是jvm内存中某一时刻所有对象的的快照。通常用于定位java程序的内存泄露或者优化内存。通常可以通过以下几种方式生称dump文件:

1.1 jmap

jmap -dump:[live,]format=b,file=

live是可选项,如果加上了live,那么只会dump存活的对象,不会dump将被gc的对象。 jmap的使用举例来说,假如通过jps得到进程id为19234:

jmap -dump:format=b,file=heap.hprof 19234

注意: jmap是实验性质的,并且不会长久支持的(This command is experimental and unsupported)

1.2 jcmd

jcmd的功能非常多,用来向jvm发送请求。使用jcmd命令必须是在和jvm进程同一个机器上运行。使用jcmd生成head dump的命令是:

jcmd GC.heap_dump [-all]

从试验来看,这里的file-path须要是绝对路径,不能是相对路径。 all是可选项,不写all就类似jmap写上了live。使用举例如:

jcmd 19234 GC.heap_dump -all /tmp/dump.hprof

1.3 自动捕获head dump文件

可以通过加入jvm参数,当程序出现oom的时候,自动产生heap dump文件

java -XX:+HeapDumpOnOutOfMemoryError

该参数默认情况下会在我们启动java进程的目录下,产生一个名字叫 java_pid.hprof 的head dump文件。如果我们希望将head dump生成在其他目录或者文件,可以使用如下参数:

java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=

当然还有其他生成head dump文件的方式,具体可以参考java-heap-dump-capture

2 GC root

2.1 概念

Garbage Collection Roots.

深入理解java虚拟机中提到,可作为GC Roots的对象包括下面几种:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法去中常量引用的对象
  4. 本地方法栈JNI引用的对象

怎么理解呢?

  1. 首先对于上述的第一点应该注意是一个虚拟机栈而不是方法栈,每个java线程有一个虚拟机栈
  2. 其次为什么这些可以作为GC root,其实比较好理解,因为栈中的对象肯定是正在使用的,所以可以从这些对象开始遍历,然后得出所有还在引用的对象;
  3. 最后,GC root到底是对象还是引用呢?可以理解为这里的引用就是对象,因为对于Java语言(非字节码)来说单独的引用(没有指向对象的引用)没有意义。也就是说我们写了个引用但是没有赋值,其实和没写是一样的。可以通过2.2的举例来加深下理解

2.2 举例

我们可以用MAT来更详细的理解:

public static void main(String[] args) throws Exception {
Stu stu = new Stu();
stu.teacher = new Teacher(); while (true) {
Thread.sleep(1000);
}
}

使用jcmd生成heap dump文件,用MAT打开后,搜索Teacher,然后我们看下这个类对应对象的“Path to gc root”:

小黄点表示这是个GC root. 这里具体表示这个是当前线程栈中的变量,类型是上一行的Stu类型。所以这里GC root就是引用了一个Stu对象的栈中的引用,你也可以理解为这个就是个Stu的一个对象。

注意:一个对象可以有多个GC root,同样在MAT上看也就是多条“Path to gc root”

3 使用MAT分析heap dump

了解了如何生成heap dump和对gc root有了进一步的了解,我们可以用MAT来进一步分析heap dump

3.1 打开

MAT默认没有显示unreachable objects,在使用前我们先勾选上

Preferences -> Memory Analyzer

然后勾选上Keep unreachable objects

如果之前没有勾选,后面要改的话,不会立刻生效,需要把解析的文件删除掉,重新解析打开heap dump文件

然后打开文件

File -> Open Heap Dump

3.2 Overview

Overview 显示了java堆的一些基本信息,比如大小、对象个数等,也包括一个对象所占内存比例的饼图,有助于我们直观上去查看占用内存比较大的对象

3.3 Histogram

Histogram即直方图,是以类的粒度来显示,可以使用正则表达式搜索感兴趣的类

如图中我们搜索Teacher,出现一个匹配项;Objects列为1,表示有一个Teacher的对象;Shallow Heap和Retained Heap的概念不在这里阐述了,简单来说Shallow Heap就是对象本身的大小,Retained Heap是指当对象释放后,引起其他对象释放总共大小,Retained Heap和支配树(dominator tree)概念有关系。一般情况下在分析的时候,我们会按照Retained Heap大小来排序,占用比较大的很有可能就是引起oom的对象。

前面说了Histogram是类粒度的,可以右击来显示该类的对象

“with incomming references”表示显示对象和引用该对象的对象,如下图。左边的黑色字体表示变量名,而变量名的类型是它的上一行的左边的类。

看到对象后,我们一般右击来看下对象的GC root,来确定对象没有被释放的原因,有两个选项

  1. 右击 -> path to gc roots -> exclude all phantom/weak/soft etc. references
  2. 右击 -> merge shortest paths to gc roots -> exclude all phantom/weak/soft etc. references

两个的区别是1是显示从该对象到gc roots的路径,而且会显示所有的gc roots(一个对象的gc root可以有多个); 2显示的是从gc roots到对象的路径,而且只显示最短的一条路径。 gc root的显示在2.2中已经显示过了

一般通过分析gc root的路径和逻辑代码,就可以很容易确定oom或者内存泄露的原因了

3.4 dominator tree

dominator tree即支配树。支配树的概念可以参考 支配树。需要注意的是,支配树并不等于path to gc roots。

Histogram是类粒度的,可以找到哪个类占用的堆内存比较多;dominator tree是对象粒度的,可以用来查看哪个对象引起占用堆内存比较大。

4 总结

一般来说对heap dump的分析是个比较综合的过程,通过Histogram和dominator tree,通过gc roots和源码综合分析,可以得出最后的结论

5 参考

  1. https://www.baeldung.com/java-heap-dump-capture
  2. https://help.eclipse.org/luna/index.jsp?topic=%2Forg.eclipse.mat.ui.help%2Fconcepts%2Fgcroots.html&cp=37_2_3
  3. https://stackoverflow.com/questions/26232733/thread-as-a-gc-root
  4. https://www.zhihu.com/question/47258557
  5. https://blog.csdn.net/jji8877032/article/details/84503063
  6. http://www.lightskystreet.com/2015/09/01/mat_usage/

GC root & 使用MAT分析java堆的更多相关文章

  1. MAT工具定位分析Java堆内存泄漏问题方法

    一.MAT概述与安装 MAT,全称Memory Analysis Tools,是一款分析Java堆内存的工具,可以快速定位到堆内泄漏问题.该工具提供了两种使用方式,一种是插件版,可以安装到Eclips ...

  2. 使用MAT分析Java内存

    Overview MAT(Memory Analyzer Tool) 是一个JAVA Heaper分析器,可以用来分析内存泄露和减少内存消耗.分析Process showmap中的/dev/ashme ...

  3. google-perftools 分析JAVA 堆外内存

    google-perftools 分析JAVA 堆外内存 分类: j2se2011-08-25 21:48 3358人阅读 评论(4) 收藏 举报 javahbasehtml工具os 原文转自:htt ...

  4. Java虚拟机八 分析Java堆

    常见的内存溢出的原因及其解决思路 1.堆溢出: 由于大量的对象都直接分配在堆上,因此它最有可能发生溢出.因为大量对象占据了堆空间,而这些对象都持有强引用,导致无法回收,当对象大小之和大于堆空间时就会发 ...

  5. 分析java堆

    内存溢出(OutOfMemory) OOM 堆溢出 直接内存溢出 永久区溢出

  6. 使用jmap和MAT分析JVM堆内存

    http://blog.csdn.net/alli0968/article/details/52460008

  7. JVM探秘:MAT分析内存溢出

    本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. MAT是分析Java堆内存的一个工具,全称是 The Eclipse Memory A ...

  8. Android开发从GC root分析内存泄漏

    我们常说的垃圾回收机制中会提到GC Roots这个词,也就是Java虚拟机中所有引用的根对象.我们都知道,垃圾回收器不会回收GC Roots以及那些被它们间接引用的对象.但是,对于GC Roots的定 ...

  9. 你不知道的Eclipse的用法:使用MAT分析Android的内存

    如果使用DDMS确实发现了我们程序中存在内存泄露,那如何定位到具体出现问题的代码片段,最终找到问题所在呢?如果从头到尾分析代码逻辑,那肯定会把人逼疯,特别是在维护别人写的代码的时候.这里介绍一个极好的 ...

随机推荐

  1. 巧用 CSS 把图片马赛克化

    一.image-rendering 介绍 CSS 中有一个有趣的特性叫 image-rendering,它可以通过算法来更好地显示被缩放的图片. 假设我们有一张尺寸较小的二维码截图(下方左),将其放大 ...

  2. mac上Navicat新建数据库3680错误解决办法

    mac上Navicat新建数据库3680错误解决办法 1.在设置里关闭mysql,若不能关闭,在终端输入: sudo /usr/local/mysql/support-files/mysql.serv ...

  3. 【C#基础概念】元数据 metadate

    元数据是指"描述资料的资料".它被用来概述资料的基础信息,以简化查找过程与方便使用[6]. 创建资料的方法 资料的用途 创建的时间与日期 资料的创建者或作者 资料被创建在电脑网络的 ...

  4. [iptables] 基于iptables实现的跨网络通信

    描述 在很多业务场景下,会遇上很多诡异的需求,不仅限于文章提及的需求,还有各种五花八门的需求,大部份的这些需求的产生都是来源于以前设计.规划上导致的问题.所以我们都会想尽办法为客户解决问题,维护好客户 ...

  5. 《Java编程思想》学习笔记(详细)

    目录 01 对象导论 02 一切都是对象 03 操作符 04 控制执行流程 05 初始化与清理 06 访问权限控制 07 复用类(继承) 08 多态 09 接口 10 内部类 11 持有对象 12 通 ...

  6. 转载-公司项目部署交付环境预检查shell脚本

    大型项目环境预检查脚本,根据自己实际情况修改脚本中变量,给大家一个思路,转载请注明出处~ 转至:https://www.cnblogs.com/gaohongyu/p/13738526.html #! ...

  7. linux访问控制列表 ACL实现文件权限设置

    ACL:Access Control List,实现灵活的文件权限管理 除了文件的所有者,所属组和其它人,可以对更多的用户设置权限 CentOS7 默认创建的xfs和ext4文件系统具有ACL功能 A ...

  8. 如何恢复 iCloud 已删除文件

    原文链接 问题 今天在查找之前的 C++ 笔记时,突然发现之前的资料全没了,整个 Cpp 文件夹内就只剩下了三个文件,怎么形容当时的心情呢,应该说是一下就跌倒了谷底,感觉之前的心血全白费了,有种深深的 ...

  9. 关于SQL Server 各种安装失败均失败,报错“等待数据库引擎恢复句柄失败”的经验分享

    最近安装SQL 2019遇到这个问题,试过自己合网上几乎所有办法,怎么都安装不上,最后在微软社区解决了,由于这个问题比较特殊,并且网上几乎没有正确的决绝方案,因此将我的解决过程及经验记录分享一下,也为 ...

  10. CF498B题解

    咋黑色啊,这不是看到数据范围就去想 \(O(nT)\) 的做法吗? 然后仔细想想最靠谱的就是 DP. 设 \(dp[n][T]\) 表示听完第 \(n\) 首歌,总共听了 \(T\) 秒. 很明显有 ...