内存分析工具MAT
首先介绍一下MAT的安装
下载地址:https://eclipse.org/mat/downloads.php
选择自己系统相应的版本下载,下载完得到一个zip文件,解压后双击EXE文件就可以直接使用了
使用jmap得到的.hprof 文件,使用MAT工具打开进行进一步的分析,选择第一个Leak Suspects Report
Histogram 可以列出内存中的对象,对象的个数以及大小,需要重点关注
它按类名将所有的实例对象列出来,点击表头(Class Name)可以排序,第一行输入正则表达式可以过滤筛选 ;
Shallow Heap :一个对象内存的消耗大小,不包含对其他对象的引用;
Retained Heap :是shallow Heap的总和,也就是该对象被GC之后所能回收的内存大小;
在某一项上右键打开菜单选择 list objects :
with incoming references 将列出哪些类引入该类;
with outgoing references 列出该类引用了哪些类
Dominator Tree可以列出那个线程,以及线程下面的那些对象占用的空间
可以列出内存中存活的大对象列表,优点是有Percentage字段,可以看各种情况的百分比。
分组工具可以根据自己的需求分组查找,默认根据class分组,本文中是根据 package分组,建议按package进行分组,可以清楚的跟进自己写的包的情况
快速找出某个实例没被释放的原因,可以右健 Path to GC Roots-->exclude all phantom/weak/soft etc. references
它展示了对象间的引用关系,比如SSLSocketImpl @0xa124b208被PushNotificationManager 实例中的socket属性所引用。
Top consumers通过图形列出最大的object
多种维度(包括 类大小、类加载器、包名)展示占用内存比较多的对象的分布,从而定位内存资源主要耗费在哪些地方!
Leak Suspects通过MA自动分析泄漏的原因,需要重点关注
Java 的内存泄漏问题比较难以定位,下面针对一些常见的内存泄漏场景做介绍:
- 持续在堆上创建对象而不释放。例如,持续不断的往一个列表中添加对象,而不对列表清空。这种问题,通常可以给程序运行时添加 JVM 参数
-Xmx
指定一个较小的运行堆大小,这样可以比较容易的发现这类问题。 - 不正确的使用静态对象。因为 static 关键字修饰的对象的生命周期与 Java 程序的运行周期是一致的,所以垃圾回收机制无法回收静态变量引用的对象。所以,发生内存泄漏问题时,我们要着重分析所有的静态变量。
- 对大 String 对象调用 String.intern()方法,该方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。而在 jdk6 之前,字符串常量存储在
PermGen
区的,但是默认情况下PermGen
区比较小,所以较大的字符串调用此方法,很容易会触发内存溢出问题。 - 打开的输入流、连接没有争取关闭。由于这些资源需要对应的内存维护状态,因此不关闭会导致这些内存无法释放。