Memory Analyzer (MAT) 在实际开发中的使用
文章目录
- Memory Analyzer (MAT) 在实际开发中的使用
- 概述
- 注意点
- 基本使用
- 检查概述
- 获取直方图
- View the Dominator Tree
- 到GC根的路径
- 使用示例
- 制作堆dump
- HeapDumpOnOutOfMemoryError
- Jmap 生成堆Dump
- Mat打开堆快照
- Histogram
- Thread Overview
- 执行内存泄露报告
- 列出大对象
- 查看对象占用树
- 元素介绍
- GcRoots
- Shallow Heap
- Retained set
- with incoming references
- with outgoing references
- 参考文献
概述
MAT,全称Memory Analysis Tools,是一款分析Java堆内存的工具,可以快速定位到堆内泄漏问题。该工具提供了两种使用方式,一种是插件版,可以安装到Eclipse使用,另一种是独立版,可以直接解压使用。
官网地址:Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation
注意点
- 运行独立版本的内存分析器所需的最低
Java版本是Java 17,下载地址 https://pan.baidu.com/s/11IZ5m2D41r1S8Anu84H0ZQ?pwd=makq

- 如果堆文件实际大小很大比如
8G,但是用Mat打开后内存信息只有1G,那么可以通过下面的设置显示无法访问对象的详细信息,需要删除之前导入进来的重新导入

基本使用
检查概述
- 通过文件> 打开堆转储…打开堆转储…查看概述页。 如果您有可用的堆转储,请立即尝试打开堆转储。

在右侧,您可以找到转储的大小和 类、对象和类装入器。
如果转储的总大小远小于 文件是可能的 堆转储包含许多垃圾 对象 在下一个垃圾桶时丢弃 收集。显示无法访问对象的步骤见注意点中描述的方法。
获取直方图
- 从工具栏中 直方图图标选择直方图图标以列出每个类的实例数, 浅尺寸(
ShallowHeap)和保留尺寸(Retained Heap)

-
浅堆是一个对象所消耗的内存,
X的保留堆是X的保留集合中所有对象的浅大小之和,即X保留的存活内存。
View the Dominator Tree
- 支配树显示堆转储中最大的对象。树的下一层列出了那些对象,如果对父节点的所有传入引用被删除,这些对象将被垃圾收集。支配树是一种强大的工具,用于研究哪些对象使哪些其他对象保持存活。同样,树可以按照类加载器(例如组件)和包分组,以简化分析。

到GC根的路径
- 从对象到
GC根的(反向)引用链——所谓的GC根路径——解释了为什么对象不能被垃圾收集。该路径有助于解决Java中的经典内存泄漏:这些泄漏的存在是因为即使程序逻辑不再访问对象,对象仍然被引用。

使用示例
制作堆dump
HeapDumpOnOutOfMemoryError
- 其实在很多时候我们是不知道何时会发生
OOM,所以需要在发生OOM时自动生成dump文件。其实很简单,只需要在启动时加上如下参数即可。HeapDumpPath表示生成dump文件保存的目录。
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\tmp
- 当系统堆溢出的时候会自动生成快照文件,项目上一般都会配置这个参数
- 内存溢出
Idea显示如下:
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to java_pid25396.hprof ...
Heap dump file created [1486916275 bytes in 5.168 secs]
Jmap 生成堆Dump
- 首先要查找运行的
Java程序的pid,然后使用jmap命令生成dump文件。file后面是保存的文件名称,1246则是java程序的PID。
jmap -dump:format=b,file=user.dump 1246
Mat打开堆快照
- 模拟堆栈溢出,如下图所示,从图中可以看出大对象占用
800M左右,RetainedSIze占用637.4M

Histogram
- 列举类的实例信息,从这里面明显的可以看到,这个对象没有
GCRoot而且占用比较大,很有可能是内存泄露的地方

Thread Overview
- 线程分析概览,展示出了所有的线程,主线程,以及各个线程中的浅堆和深堆占用的大小,类加载器,是否守护线程等信息

执行内存泄露报告
- 点击
Leak Suspects查看存在内存泄露的地方

列出大对象
- 从下面的这个图可以判断出程序中存在死循环

查看对象占用树
- 在此视图中列出了每个对象(
Object Instance)与其引用关系的树状结构,同时包含了占用内存的大小和百分比。通过Dominator Tree视图可以很容易的找出占用内存最多的几个对象(根据Retained Heap或Percentage排序);

元素介绍
GcRoots
GC Root(Garbage Collection Root)是指在Java虚拟机中被直接或间接引用的对象集合,它们被认为是存活对象,不能被垃圾回收器回收。GC Root的作用是为垃圾回收器提供一个初始的扫描位置,以便确定哪些对象是可达的,哪些对象是不可达的。垃圾回收器会从GC Root开始扫描,并标记所有可达对象,最终将不可达对象回收掉。
GC Root包括以下几种类型:
-
虚拟机栈中引用的对象
-
方法区中类静态属性引用的对象
-
方法区中常量引用的对象
-
Native方法中引用的对象 -
活动线程中的对象
-
当前类加载器加载的类的对象
-
例如下面的图中
GCRoots没有到达object5、object6、object7,因此他们三标记为可以被回收

Shallow Heap
Shallow Heap为对象自身占用的内存大小,不包括它引用的对象。
Retained set
- 对象本身和他持有引用的对象和这些对象的
retained set所占内存大小的总和


with incoming references

- 对象
A和对象B持有对象C的引用 - 对象
C持有对象D和对象E的引用 - 对象
C的Incoming References:拥有对象C的引用的所有对象都称为Incoming references。在此示例中,对象C的Incoming references是对象A、对象B和C的类对象
with outgoing references
- 对象
C的Outgoing References:对象C引用的所有对象都称为Outgoing References。在上面图中,对象C的outgoing references是对象D、对象E
参考文献
- 一文让你理解什么是shallow heap及retained heap - 知乎 (zhihu.com)
- Shallow Heap 和 Retained Heap的区别_shallow heap和retained heap什么区别-CSDN博客
- JVM 内存分析神器 MAT: Incoming Vs Outgoing References 你真的了解吗?-腾讯云开发者社区-腾讯云 (tencent.com)