.hprof 文件: 是 java 项目的
Heap Dump
文件,也叫内存映像文件、内存快照文件,可以存放一个 java 进程在某个时间点的内存快照。生成 Heap Dump 文件的方式有两种:一是使用jmap
命令手动导出,二是启动脚本中添加-XX:+HeapDumpOnOutOfMemoryError
参数自动导出。本文中只涉及第二种。
1.新建一个文本文件,命名为 HeapOOM.java,内容如下:
import java.util.ArrayList;
import java.util.List;
public class HeapOOM {
static class User {}
public static void main(String[] args) {
List<User> list = new ArrayList<>();
while (true) {
list.add(new User());
}
}
}
2.打开控制台,执行如下命令编译 java 文件:
javac HeapOOM.java
3.使用如下命令运行 java 文件:
java -Xms10M -Xmx10M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ HeapOOM
-Xms10M
堆内存最小10M;-Xmx10M
堆内存最大10M;-XX:+HeapDumpOnOutOfMemoryError
内存溢出时自动导出堆内存快照;-XX:HeapDumpPath=./
内存快照保存位置,不指定默认当前路径下载地址: https://www.eclipse.org/mat/downloads.php
点击 Download。
注意:目前最新的版本 Memory Analyzer 1.13.0 Release,是只支持在 JDK 11 下运行的
如果想下载 JDK8 下运行的版本,可以点击 Other Releases > Previous Releases。
选择版本:Memory Analyzer 1.9.2 Release
双击 exe 文件启动:
注意: 如果 hprof 文件太大,需要调整它的内存才可以完成大 dump 文件的加载,这个配置文件需要 exe 启动后会自动生成:
点击 Open a Heap Dump,选择一个 hprof 文件打开:
概览中,我们可以看到对象所占的比例及排序。显然有个对象不正常,一共上限 10M 的内存占用了 6.9 M。
点击下方的 Leak Suspects,可以查看 MAT 的详细分析结果,猜测导致堆栈溢出的原因:
根据上图可以看到有一个猜测的原因:
毫无疑问是对象实例过多导致的内存溢出,具体是哪个对象呢,下一步怎么分析呢?
点击下图所示柱状图(Histogram)查看对象实例数量排序,在 Regex 中可以用输入正则表达式把自己的包名,输入后回车过滤:
这里的 User 实例有 36w 个,显然不正常,我们可以查下是谁引用的:
我们可以看到是 main 线程中引用了这些对象。(当前示例较为简单,如果是项目中可以明确看到是哪个类中的引用导致的)
支配树: MAT 提供了一个成为支配树(Demonitor Tree)的对象图。支配树体现了对象实例间的支配关系。在对象引用图中,所有指向对象 B 的路径都经过对象 A,则认为对象 A 支配对象 B。如果对象 A 是离对象 B 最近的一个支配对象,则认为对象 A 为对象 B 的直接支配者。
支配树是基于对象间的引用图所建立的,它有以下基本性质:
我们可以理解为支配图就是用来查看类使用内存比例的,图中使用最多的类对应溢出原因猜测中的内存使用率 92.88%。
以上就是 MAT 分析 .hprof 文件的常用功能。
整理完毕,完结撒花~
参考地址:
1.导出dump文件及MAT安装分析,https://blog.csdn.net/lixiangchibang/article/details/124721472
2.【JVM笔记】支配树(Dominator Tree),https://blog.csdn.net/lijibai_/article/details/126526375