重庆住房和城乡建设部网站的打印准考证,网站空间可以自己做服务器,郑州建立网站,可以做网站的编程有什么原创/朱季谦
一、MAT概述与安装
MAT#xff0c;全称Memory Analysis Tools#xff0c;是一款分析Java堆内存的工具#xff0c;可以快速定位到堆内泄漏问题。该工具提供了两种使用方式#xff0c;一种是插件版#xff0c;可以安装到Eclipse使用#xff0c;另一种是独立版…
原创/朱季谦
一、MAT概述与安装
MAT全称Memory Analysis Tools是一款分析Java堆内存的工具可以快速定位到堆内泄漏问题。该工具提供了两种使用方式一种是插件版可以安装到Eclipse使用另一种是独立版可以直接解压使用。 我把独立版MAT安装包放到了网盘上方便直接下载———— 链接百度网盘 请输入提取码 提取码rhb5 独立版解压后其内部文件是这样的—— 这里有一个MemoryAnalyzer.ini文件里面有一个Xmx参数默认是-Xmx1024m这代表MAT的最大内存大小根据具体分析的dump文件大小来做适当调整。
点击MemoryAnalyzer.exe启动完成后即可以使用它来检查定位内存泄漏相关的问题了。 二、内存泄漏案例分析
下面我会结合一个小案例来分享MAT的使用。
首先用IDEA建立一个测试类——
public class example {public static void main(String[] args) {ListUser listnew ArrayList();while (true){list.add(new User());}}
}class User {private String namedemo;public User() {}
}
给这个测试类设置虚拟机参数设置如-Xms2m -Xmx2m -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPathD:/local_system/git/demo/heapdump.hprof
这几个参数的意义是
-Xms2m -Xmx2m堆最小内存为2M最大内存为2M。这里没有显示设置新生代大小它会自动分配新生代大小分配完剩下的就是老年代大小了。
-XX:HeapDumpOnOutOfMemoryError指发生内存溢出的时候会自动生成一个二进制的堆快照文件这个快照文件以.hprof后缀结尾。用MAT分析堆内存信息就是利用这个.hprof文件。除了可以设置相应的虚拟机参数外还可以通过jmap指令来获取到某个进程的堆快照文件执行指令格式是
jmap -dump:formatb,filedumpfile.hprof pid例如jmap -dump:formatb,file20210618.dump 7132那么这里20210618.dump就是自定义的dump堆转储文件名字而7132是进程ID。只是使用jmap指令可能有一点不好的地方是内存溢出是某个时间点发生的事情jmap指令去获取到dump文件存在时间差问题。而HeapDumpOnOutOfMemoryError则是在发生内存溢出时同时生成的故而会更准确些。
-XX:HeapDumpPathD:/local_system/git/demo/heapdump.hprof内存溢出产生的堆快照自动存储路径可以自定义指定路径。
其实在实际生产环境里除了这些基本参数外还有其他的JVM参数这些参数都是用来调优的重点所在。
这里暂且以这些参数做实验在运行IDEA时可以将这些参数设置在IDEA的“Run/Debug Configurations”弹出框的VM options输入框里如下截图所示—— 按照以上方式设置好后就可以运行该案例代码了运行一会儿后就会出现以下提示—— 这表明该代码已经发生内存溢出了即ArrayList存储的对象大小已经超过堆内存导致无法进行垃圾回收也就是出现内存泄漏进而导致内存溢出。当然在本地是可以看到这么简单的异常提示的但是在线上服务器上就没有那么明显的内存溢出提示就需要获取到产生的堆快照dump文件然后再进一步分析堆快照信息。 三、使用MAT分析堆转储dump文件
我们将这个heapdump.hprof文件导入到MAT里。启动MAT点击File选择Open Heap Dump然后选择对应的hprof文件。 在弹出框处选择Leak Suspects Report这是指内存泄漏报告—— 点击Finish后展示Overview主页面如下—— Overview主页面显示应用程序内存使用情况的概览中间的饼图按retained size来显示最大的对象。注意一点是在MAT中会有两种大小表示一个是Retained size还有一个是Shallow Size那么两者有什么区别呢
Shallow Size表示对象自身占用的内存大小不包括它引用的对象。Retained size当前对象内存大小当前对象直接或间接引用的对象大小全部的总和简单理解就是当前对象被GC后总共能释放的内存大小。 1.Details显示的是dump文件的情况表示堆大小为1.1MB有516个class,40.2k个Object3个类加载器等 2.功能视图模块 3.报表模块 我比较喜欢用Actions的Histogram视图和Reports的Leak Suspects报表Histogram视图是以类为维度来显示其实例数和每个类的使用内存量可以协助我们查询哪些类对象占用较大内存Leak Suspects则可以协助分析内存泄漏的原因所在。
- Histogram视图 以Class Name为维度分别展示各个类的对象数量Shallow SizeRetained size。这里有一个疑惑是Shallow Size和Retained size没有显示是以什么为单位的它默认是以byte为单位的若要显示地让单位展示出来可以这样设置点击Window-Preferences 选择最后一项点击Apply and Close—— 再重新打开Histogram视图就会生效了单位就显示出来了—— 根据这个Histogram视图我们可以发现com.example.demo.User数量和占用内存大小都比较高同时说明了该User对象一直没有被GC回收掉这时可以右击弹出框有以下一些菜单选项—— List objects 使用List Object可以查看对象引用关系这里查看引用功能包括本对象引用外部对象with outgoing references与外部对象引用本对象with incoming references。 with outgoing references 使用该功能可以查看对象内部都引用了哪些外部对象例如这里的User其引用外部对象情况如下 对照这个案例的代码可见在创建这个User对象时内部属性name就会指向一个字符串地址换言之该User对象内部有个引用指向了一个name字符串地址。 with incoming references 使用该功能可以查看该对象都被哪些外部所引用了——
在案例代码当中是以list.add(User)来不断存储User对象的如截图所示通过MAT可确定存在一个ArrayList集合一直引用该User对象。
在实际开发当中一个对象可能引用了诸多其他外部对象或者被诸多外部对象所引用若一直引用着说明某个对象一直存在GC ROOT可达的情况反过来就意味着该被引用的对象一直无法被GC回收处理那么就可能会一直存在堆内存里进而造成内存泄漏的情况。
Merge Shortest Paths to GC Roots-exclude all phantom/weak/soft etc. references 排除其他引用只观察GC路径上强引用的对象所观察到的都是仍存活的对象。
除此之外Histogram视图仍有其他功能后期在学习过程当中不断进行完善。
- Leak Suspects报表 Leak Suspects报表很直观地展现了一个饼图图中颜色深的部分表示可能存在内存泄漏的嫌疑。每一个模块都有对应的详情信息。
这里拿模块a来讲解其详情部分有一句话很关键The memory is accumulated in one instance of java.lang.Object[], loaded by , which occupies 617.55 KB (52.54%) bytes.The stacktrace of this Thread is available. See stacktrace. See stacktrace with involved local variables.
这句话翻译过来就是内存累积在一个“java.lang.Object[]”实例中由“”加载占用617.55 KB52.54%字节。此线程的堆栈跟踪可用。请参见stacktrace。请参阅包含局部变量的stacktrace。
点击stacktrace进入到一个页面可以看到日志信息—— 在这里从下往上看异常信息可以快速定位内存泄漏地方出现在哪个类方法里的哪行代码。
我很喜欢使用这个功能通过获取线上堆转储文件便可以通过Leak Suspects定位到内存泄漏快速定位在哪一行代码。 欢迎关注博主后续会发更多原创总结。