MAT是什么?

MAT(Memory Analyzer Tool),一个基于Eclipse的内存分析工具,是一个快速、功能丰富的JAVA heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。使用内存分析工具从众多的对象中进行分析,快速的计算出在内存中对象的占用大小,看看是谁阻止了垃圾收集器的回收工作,并可以通过报表直观的查看到可能造成这种结果的对象。

软件地址

使用说明

1、环境

安装好jdk,配置好环境变量JAVA_HOME

运行内存分析器的最低Java版本是 1.8.0 最新版本MAT已经要求17以上

注: 确保你的hprof文件没放在c盘或是桌面,因为mat软件默认会在解析的同时生成一堆文件再hprof文件的相对路径下

2、使用 Memory Analyzer Tools 获取堆存储

1、启动进程仅需单击两次。在菜单中,选择“file --> Acquire Heap Dump...” 或者有直接生成好的dump文件,则直接Open Heap Dump ,打开即可;

2、选择Acquire Heap Dump后。您可以看到正在运行的Java进程;选择你所需要分析的java进程,我这里是选择项目的主模块,因为项目为一个微服务架构体系。您会在底部注意到为堆转储文件自动生成的路径。顺便说一句,我建议选择一个仅包含转储的文件夹,接着finish即可。MAT除了它之外还生成许多其他文件。

3、finish完后,等待堆转储写入磁盘并由MAT解析。对于巨大的Java堆大小,这些操作可能需要一些时间。右下角会有进度条加载

4、加载完后,随后会弹出如下一个新的对话框,提示您进行快速概述,默认选择第一个(泄漏可疑报告),finish即可。

5、自动展开如下该窗口,即可进行内存分析;

6、实际上,这种方式要求该进程仍在运行。这是一个调试/开发用例 。

7、介绍一下下面的Actions的几个标签,重点介绍Histogram 和 Leak Suspects

  • Histogram :可以列出内存中的对象,对象的个数以及大小。
  • Dominator Tree:可以列出那个线程,以及线程下面的那些对象占用的空间。
  • Top consumers:通过图形列出最大的object。
  • Leak Suspects:通过MA自动分析泄漏的原因。

8、类型详细介绍

Histogram :Lists number of instances per class

Histogram是我们使用最多的一个,可以列出内存中的对象,对象的个数及其大小

  1. Class Name : 类名称,java类名
  2. Objects : 类的对象的数量,这个对象被创建了多少个
  3. Shallow Heap :一个对象内存的消耗大小,不包含对其他对象的引用
  4. Retained Heap :是shallow Heap的总和,也就是该对象被GC之后所能回收到内存的总和

点击Objects 或者 Shallow Heap 可以直观看到,定位到项目上具体哪一个实体所耗内存情况,

然后单击右键,Lists Objects ---> with incoming references 可以具体看到那些对象引用了。

Shallow Size

对象自身占用的内存大小,不包括它引用的对象。
针对非数组类型的对象,它的大小就是对象与它所有的成员变量大小的总和。当然这里面还会包括一些java语言特性的数据存储单元。
针对数组类型的对象,它的大小是数组元素对象的大小总和。

Retained Size

Retained Size=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C, C就是间接引用)
换句话说,Retained Size就是当前对象被GC后,从Heap上总共能释放掉的内存。
不过,释放的时候还要排除被GC Roots直接或间接引用的对象。他们暂时不会被被当做Garbage。

关于的详细讲解,可以查看Shallow heap & Retained heap,这是个很重要的概念。

Dominator Tree: List the biggest objects and what they keep alive

展示存活的大对象

我们可以看到session 占比最大;

Top Consumers: Print the most expensive objects grouped by class and by package.

这张图展示的是占用内存比较多的对象的分布,下面是具体的一些类和占用。

按等级分布的类使用情况,其实也就是按使用次数查看,org.apache.shiro.web.session.mgt.DefaultWebSessionManager被排在第一

还有一张图是我们比较关心的,那就是按包名看占用,根据包我们知道哪些公共用的到jar或自己的包占用;

如此分析,就可以看到包和包中哪些类的占用比较高。

Leak Suspects : includes leak suspects and a system overview

自动分析内存内存泄漏的原因,可以直接定位到Class,且行数。

在报告上最醒目的就是一张简洁明了的饼图,从这份报告,看到该图深色区域被怀疑有内存泄漏,可以发现整个heap只有442.7M内存,深色区域就占了82%。所以,MAT通过简单的报告就说明了项目是有可疑代码的,具体点开详情来找到类;

在图的下方还有对这个可疑对象的进一步描述。我们可以看到内存是由org.apache.shiro.web.session.mgt.DefaultWebSessionManager 的实例消耗的,org.springframework.boot.loader.LaunchedURLClassLoader 负责这个对象的加载。这段描述非常短,但我相信您已经可以从中找到很多线索了,比如是哪个类占用了绝大多数的内存,它属于哪个组件等等。

接下来,我们应该进一步去分析问题,为什么一个 DefaultWebSessionManager 会占据了系统 82% 的内存,谁阻止了垃圾回收机制对它的回收。

接着点击 下方的 Details > ,如下:

a、可以看到 Accumulated Objects by Class in Dominator Tree【从根元素到内存消耗聚集点的最短路径】

我们可以很清楚的看到整个引用链,内存聚集点是一个拥有大量对象的集合,如果你对代码比较熟悉的话,相信这些信息应该能给你提供一些找到内存泄露的思路了。

接下来,我们再继续看看,这个对象集合里到底存放了什么,为什么会消耗掉如此多的内存。

b、 Accumulated Objects in Dominator Tree【内存消耗聚集对象信息】

在这张图上,我们可以清楚的看到,这个对象集合中保存了大量ConcurrentHashMap对象的引用,就是它导致的内存泄露。

至此,我们已经拥有了足够的信息去寻找泄露点,回到代码,你会发现原来是session 在暂存token的时候,业务需求,在每调用一次接口,session便要用map存一次token,定时任务的产生,导致项目不到一天便挂了,至此, 问题所导致内存泄露缘由已经找到,具体怎么解决暂代思考。

总结

从上面的例子我们可以看到用 MAT 来进行堆转储文件分析,寻找内存泄露非常简单,尤其是对于新手而言,这是一个很好的辅助分析工具。但是,MAT 绝对不仅仅是一个“傻瓜式”内存分析工具,它还提供很多高级功能,比如 MAT 支持用 OQL(Object Query Language)对 heap dump 中的对象进行查询,支持对线程的分析等,有关这些功能的使用可以参考 MAT 的帮助文档。