Eclipse作为JAVA非常好用的一款IDE,其自带的可扩展插件非常有利于JAVA程序员的工作效率提升。
MemoryAnalyzerTool(也叫MAT)是一款JAVA虚拟机内存映像分析工具,可以在JAVA程序运行的时候有程序抛出的异常加上已经设置好的参数(-XX:+HeapDumpOnOutOfMemory)调试出内存泄漏或者异常的位置以及原因跟踪,MemeoryAnalyzer可以对Dump出来的堆转储快照进行分析,重点是确认内存中的对象是否是有必要的,也就是要先确认到底是出现了内存泄漏(Memory Leak)还是内存溢出(Memory OverFlow)。
二、准备工作
1.Eclipse IDE:我的是安装的Eclipse Neon3,大部分版本Eclipse都支持插件安装。
名称:Eclipse Neon
下载地址:
https://www.eclipse.org/downloads/packages/release/neon/3
(我的是Windows64位的JavaEE版本)
2.Memory Analyzer Tool(MAT):由于Eclipse支持直接从URL导入包快捷安装,以及下载压缩包后导入安装,下载包在Eclipse官网中能很快找到:
名称:Memory Analyzer
版本:最新版1.7.0.20170613
官网下载地址:
https://eclipse.org/mat/downloads.php
里面有三种:
1.Eclipse导入的URL,特点:安装简单快捷,不需要自己去手动下载,直接输入URL由Eclipse帮你自动下载;
2.Eclispe导入的zip,特点:自己下载,当Eclipse自带工具下载较慢的时候可以使用自己下载然后导入zip即可;
3.独立的MemoryAnalyzer工具,特点:自行下载,不依赖于Eclipse的启动,可直接独立导入.hprof文件进行分析。
三、开始安装MAT
运行Eclipse,然后单击菜单栏上“Help=》Install New Software...”
进入软件源导入界面,你可以选择使用URL直接导入,URL导入的地址为:
http://download.eclipse.org/mat/1.7/update-site/
但是由于镜像连接不稳定性,我使用的是下载压缩包zip然后安装,压缩包下载地址为:
http://ftp.jaist.ac.jp/pub/eclipse/mat/1.7/MemoryAnalyzer-1.7.0.201706130745.zip
下载完成之后将其导入,"Add》Archive》选择你下载好的zip文件》OK":
确定之后勾选"Memory Analyzer for Eclipse IDE"下面的两项即可,这个是用于Eclipse内部使用的插件,下面一个“Stand-alone Memory Analyzer“是独立的分析工具,一般不用勾选。
之后单击“Next"等待一段时间Eclipse计算的需求和依赖文件下载完毕后,一路"next",并接受协议“Finish”即可完成安装,重启Eclispe后就可以使用MAT了。
四、MAT的简单使用
1.设置JVM参数
JVM的参数可以用于调试JVM在各种限制条件下的常见BUG,一下简单介绍几个参数:
-XX:+HeapDumpOnOutOfMemoryError //虚拟机在堆异常时生成对存储快照,后缀一般是.hprof
-Xms //Java堆的最小值,例如-Xms20m,将Java堆的最小值设置为20MB
-Xmx //Java堆的最大值,例如-Xms40m,将Java堆的最大值设置为40MB
了解了参数之后,可以对参数进行一定的设置,以便我们简单的对MAT工具进行使用测试,设置参数如下:
-XX:+HeapDumpOnOutOfMemoryError
-Xms20m
-Xmx20m
之所以将最小和最大的堆设置为一样是为了能避免堆的自动扩展,以及20MB的空间是为了让程序能尽快的占满使得内存溢出。
设置JVM的启动参数可在“Run》Run Configuration》Arguments》Vm arguments”中填写
2.编写内存溢出(Memory Leak)代码
思路:通过新建集合列表List,然后以while(true)死循环的方式使得List集合不断添加新的对象,使得其不断地占满堆空间
package com.study;
import java.util.ArrayList;
import java.util.List;
public class TestStudy {
static class OOMClass { }
public static void main(String[] args) {
List<OOMClass> list = new ArrayList<OOMClass>();
while(true) {
list.add(new OOMClass());
执行代码,发现输出如下:
注意到“java_pid24792.hprof”文件,这个文件是JVM生成的对存储快照,之后可以通过MAT工具打开,进行分析追踪,这个文件将自动保存到你的Eclipse workspace下的工作目录中,以我的为例:
3.打开MAT的Perspective
由于MAT工具需要另外打开一个工作视图(就像Eclipse EE和Java的切换视图一样),因此需要在先配置打开"Window》Perspective》Open Perspective》Other...":
选择Memory Analysis并确定:
完后之后将进入MAT的工作空间视图,你可以在Eclipse右上角进行切换回Java或者EE,由于接下来要使用MAT分析,因此就暂时不切回之前的Java了
4.打开需要分析的堆转储快照.hprof文件
由于MAT是依赖于生成的堆转储快照,而不是在运行的时候自动捕获,因此,再确认进入MAT的工作空间后,点击"File》Open Heap Dump》选择刚生成的“java_pid24792.hprof”文件,一直默认就可以查看内存问题的分析图表以及GC根
你可以进行一些分析操作,可以看到Action下的几个选项:
a.Histogram:列出每个类的实例列表;
b.Dominator:列出最大的对象和他们存在的东西;
c.Top Comsumer:打印按类和包分组的最昂贵的对象;
d.Duplicate Classes:检测由多个类加载器加载的类。
5.使用MAT找出问题存在的对象
由于是一个简单的问题,因此我们直接选择Dominator,可以直接以百分比的形式打印出对象所占的百分比,一般的内存溢出大部分情况都是有某一个对象过多存在而未被GC回收导致,所以可以点开最大百分比的类一级级找,不难找到问题所在:
可以看到列出额其中的25条,还有810300条目未列出,这81万个对象占据了97.36%的堆空间,因此不难发现是OOMClass类的对象生成过多为未被回收导致内存溢出。
6.进一步追踪问题源并进行定位
在"default_report org.eclipse.mat.api:suspects"的标签分页中
在"Program Suspect 1》Details"点击后找到"Thread Stack"中追踪出错点
看到出错点在第13行,找到对应的Java代码TestStudy的13行:
1 package com.study;
3 import java.util.ArrayList;
4 import java.util.List;
6 public class TestStudy {
8 static class OOMClass { }
10 public static void main(String[] args) {
11 List<OOMClass> list = new ArrayList<OOMClass>();
12 while(true) {
13 list.add(new OOMClass());
14 }
15 }
找到了追踪的出错位置,以上就是使用Memory Analyzer工具完成的堆栈分析。