1、工具简介

MAT,全称Memory Analysis Tools,是一款分析Java堆内存的工具,该工具提供了两种使用方式,一种是插件版,可以安装到Eclipse使用,另一种是独立版,可以直接解压使用。由于现在Java开发的编译器基本都是IDEA了,因此本文主要讲独立版使用。
生产环境都是Linux系统,这里就不总结windows下安装使用MAT的方法了,本节的教程下载安装到获取报告都是在Linux系统上,分析报告是将文件下载到本地windows系统上分析。

2、下载安装

下载地址:Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation
image.png
将下载好的安装包上传到服务器上,解压后即可使用。
最新版本的MAT工具:Memory Analyzer 1.12.0 Release,jdk要求至少11以上了…看来还得安装之前的版本。如果是JDK1.8,可以下载Memory Analyzer 1.7.0 Release 版本。
image.png

3、获取报告

3.1 demo

思路就是写一个可以造成OOM的程序,放到环境中用java -jar命令启动。项目中就一个主类,主类里就一个Main方法,主类代码如下:
MainClass:

  1. import java.util.ArrayList;
  2. import java.util.List;
  3. public class MainClass {
  4. public static void main(String[] args) {
  5. List<User> list = new ArrayList<>();
  6. while (true) {
  7. list.add(new User());
  8. }
  9. }
  10. static class User {
  11. private final String name = "demo";
  12. public User() {}
  13. }
  14. }

通过IDEA在本地windows环境上打出jar包,再上传到Linux环境上,打jar包的坑参考这篇文章:解决IDEA打Jar包找不到或无法加载主类问题

将生成的jar包传到环境上,用java -jar命令启动这个jar包,需要加上JVM启动参数,将堆内存分配2M,使其快速达到OOM,具体启动命令如下:

  1. java -Xms2m -Xmx2m -XX:+HeapDumpOnOutOfMemoryError
  2. -XX:HeapDumpPath=/opt/demo/ -jar ./matDemo.main.jar

JVM启动参数说明:

  • -Xms:表示初始化堆的大小及该进程刚创建出来的时候,JVM的堆的大小,一旦对象容量超过了JAVA堆的初始容量,JAVA堆将会自动扩容到-Xmx大小;
  • -Xmx:堆内存可以扩展到的最大值;
  • -XX:+HeapDumpOnOutOfMemoryError:指发生内存溢出的时候,会自动生成一个二进制的堆快照文件,这个快照文件以.hprof后缀结尾。用MAT分析堆内存信息,就是利用这个.hprof文件;
  • -XX:HeapDumpPath:内存溢出产生的堆快照自动存储路径,可以自定义指定路径。

在环境上运行,结果如下图所示:
image.png
如果没有指定XX:+HeapDumpOnOutOfMemoryError参数,还可以通过jmap命令来手动获取某个进程的堆快照文件,具体可以参考我这篇文章:https://www.yuque.com/docs/share/a58fa76d-d64f-4474-ab8b-d1614a212c97?# 《JDK工具包》

3.2 使用MAT获取分析报告

将2下载安装中下载下来的zip包上传到服务器指定目录中,解压:

  1. unzip -d ./ MemoryAnalyzer-1.7.0.20170613-linux.gtk.x86_64.zip

解压后如下图所示:
image.png
对上图文件进行说明:

  • MemoryAnalyzer.ini:MAT工具的配置文件,里面有一个参数-Xmx很重要,因为生产环境上的JVM堆内存一般都有几个G,而MemoryAnalyzer.ini中的-Xmx默认是1G,因此需要将-Xmx调大,一般是JVM堆内存 +1G;
  • ParseHeapDump.sh:MAT工具提供了ParseHeapDump.sh脚本来启动,脚本内容就是通过传入参数来启动MemoryAnalyzer;
  • MemoryAnalyzer:真正的MAT工具。

生成分析报告:

  1. ./ParseHeapDump.sh java_pid14441.hprof org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components

结果如下图所示:
这里出现了个很奇怪的现象:
image.png
执行完命令后,会在mat目录下生成3份.zip结尾的报告,这些报告大致的内容是:

  • Leak_Suspects:该文件是我们排查内存泄漏和内存溢出的主要文件,里面可以看到内存的圆饼图和可疑的堆栈跟踪;
  • Sytem_Overview:系统总览。这个文件是JVM内存分析报告的大纲,可以通过这个大纲,看到所有对象、线程、内存占用的情况;
  • Top_Components:顶部组件。这个文件记录了一些内存使用浪费的,或者可以优化的类信息。

    注意:生成环境中使用MAT工具生成分析报告zip文件,JVM的堆快照文件一般也要几个G,由于MAT工具需要把整个堆快照文件读取到内存中,要求MAT工具所在的服务器上空余内存至少要大于快照文件大小,因此一般会在一个空闲内存较多的专门的服务器去跑MAT工具。

4、分析报告查找原因

3.2步中生成的zip文件,我们一般不在Linux服务器上看分析报告,而是把zip文件传到你自己的研发windows环境上看,生成的zip文件,下载到本地后,解压可以通过浏览器打开。
我比较喜欢用Actions的Histogram视图和Reports的Leak Suspects报表,Histogram视图是以类为维度来显示其实例数和每个类的使用内存量,可以协助我们查询哪些类对象占用较大内存;Leak Suspects则可以协助分析内存泄漏的原因所在。
Histogram视图:
image.png
image.png
Leak Suspects报表:
image.png
Leak Suspects报表很直观地展现了一个饼图,图中颜色深的部分表示可能存在内存泄漏的嫌疑。每一个模块都有对应的详情信息。点击stacktrace可以看到详细的线程堆栈分析。

参考

MAT工具定位分析Java堆内存泄漏问题方法
Linux 系统使用Mat 进行内存泄漏分析
解决IDEA打Jar包找不到或无法加载主类问题