Eclipse Memory Analyzer是一个快速而功能丰富的Java堆分析器,可帮助您查找内存泄漏并减少内存消耗。
使用内存分析器分析数亿个对象的生产性堆转储,快速计算保留的对象大小,查看谁阻止垃圾收集器收集对象,运行报告以自动提取泄漏的嫌疑人。
应用的主要领域是内存不足错误和高内存消耗。
下载安装
http://www.eclipse.org/mat/downloads.php找寻最新稳定版本
不知道怎么下载?请参考https://www.jianshu.com/p/3b3c3a914724
解压后直接打开MemoryAnalyzer.exe
是不是感觉so亲切哟~
获取Heap Dump文件
Wow,wow什么是Heap Dump文件
Heap Dump 是一个 Java 进程在某个时间点上的内存快照。 Heap Dump 是有着多种格式的。 不过总体上Heap Dump 在触发快照的时候都保存了 java 对象和类的信息。通常在写 Heap Dump 文件前会触发一次 FullGC,所以 Heap Dump 文件中保存的是 FullGC 后留下的对象信息。
Memory Analyzer 可以用来处理 HPROF 二进制 Heap Dump 文件、 IBM 系统 dump 文件(经过处理后)、以及来自各个平台上的 IBM portable Heap Dumps (PHD)文件。
一般在 Heap Dump 文件中可以获取到( 这仍然取决于 Heap Dump 文件的类型) 如下信息:
对象信息:类、成员变量、直接量以及引用值;
类信息: 类加载器、 名称、 超类、 静态成员;
Garbage Collections Roots: JVM 可达的对象;
线程栈以及本地变量: 获取快照时的线程栈信息, 以及局部变量的详细信息。
Heap Dump 文件中并不包含内存分配信息, 所以通常无法通过 Heap Dump 文件解决是谁以及在哪里创建了哪些对象这样的问题。
MAT根据这个文件可以分析出内存泄露和高内存消耗地点。
获取Heap Dump文件的方式
官方文档上面有写获取堆转储文件的获取方式
1.通过 OutOfMemoryError 获取 Heap Dump只能在发生OOM的时候才能获取到,且这个方案适用于如下版本的虚拟机:
Sun JVM (1.4.2_12 or higher and 1.5.0_07 or higher), HP-UX JVM
(1.4.2_11 or higher) and SAP JVM (since 1.5.0)。
2.主动触发一次 Heap Dump
也可以为虚拟机设置下面的参数,这样就可以在需要的时候按下 CTRL+BREAK 组合键随时获取一份 Heap Dump 文件
-XX:+HeapDumpOnCtrlBreak
这个是oracle版本的虚拟机使用的设置啊
3.使用 HPROF agent
用 agent 可以在程序执行结束时或者收到 SIGQUIT 信号时生成 dump 文件。 使用 agent 也是要配置虚拟机参数的:
-agentlib:hprof=heap=dump,format=b
这些不太实用于我现在的需求,我希望本地能够获取到,且JVM是HotSpot类型的。
命令行输入java –version
Jconsole获取
所以对应我的需求,我使用的方式是通过JDK自带的JCONSOLE来获取。首先需要设置JVM参数,我使用的是在web服务器上面设置weblogic.
参考http://blog.csdn.net/yufan1987/article/details/8747673
具体:找到bea/user_projects/domains/domain/bin/setDomainEnv.sh文件中的这一行
MEM_ARGS="-Xms256m -Xmx512m"
export MEM_ARGS
- 1
- 2
改为
MEM_ARGS="-Xms256m -Xmx512m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+HeapDumpOnOutOfMemoryError -XX:+HeapDumpOnCtrlBreak -Xloggc:$$.gc.log"
export MEM_ARGS
- 1
- 2
打开MyEclipse,运行一个项目,然后打开任务管理器,利用jconsole
- 到weblogic这个domain下,输入jps命令,找到server对应的pid,例如cc本地
我们得到了pid 为 7568
然后继续在本目录下输入jconsole 7568
会发现打开了jconsole的一个控制台,连接,如果链接不成功。。。点击取消,出现提示,按照它提示的选项连接即可
(p1里面的true意为只获取live的对象)
找到hotspotdiagnostic树下的dumpHeap,我们输入p0 位7568.bin,点击按钮,可以在当前domain目录下看到一个文件:
这个文件就是我们的dumpHeap文件啦
jmap获取
如果支持jmap命令的话,可以使用jmap方式获取,不过这个需要Oracle JVM 的版本,如果你和我一样是HP版本那么很不幸提示:
如果是oracle的(以下为linux)
利用ps -ef | grep java 找到运行程序的进程号。
输入命令kill -3 ,就可以得到heapdump文件(在该进程对应的domain目录下)。
Memory Analyzer
对于分析和项目在同一台机器上来说,可以使用MAT来获取
参考https://community.bonitasoft.com/blog/acquire-heap-dump-mat-memory-analyzer-tool
这个需要jdk的bin中有jmap命令,jdk1.5我的版本不支持,无图。参考我刚才写的连接即可。
哎呀我们终于有了一个Heap Dump文件了,7568.bin,现在我们就可以使用MAT去分析它了
MAT使用
现在已经可以集成到Eclipse中啦。MAT可以分析多种heap dump文件,包括:
1. Sun JDK的heapdump
2. HP JDK生成的bin格式heap dump
3. IBM生成的heap dump
我们现在有的就是第二种啦,可以进行使用了哦
突然看到一点文件名必须以.hprof结尾,因为要在 MemoryAnalysisPerspective 下打开扩展名必须是这个,不懂什么原理啦,我们改个扩展名即可。
现在是7568.hprof
Overview
我们打开下好的MAT软件,FileOpen Heap Dump进入发现直接进入了Overview页面。
在右侧窗口上方的位置可以看到 heapDump 的 size,以及类、对象和类加载器的数量。
右侧窗口中最醒目的饼图直观地显示了 dump 中最大的几个对象。鼠标光标划过饼图中代表某个对象的区块时可以在左侧 Inspector 窗口中看到对象的细节,在区块上点击鼠标左键可以通过菜单项钻取到关于其对应的对象更多的细节。
我们可以看到占用很大一部分内存的有几个深色的饼区,这些就可以当做我们稍后着重看的地方
关于内存大小的显示:
Shallow Heap 表示一个对象消费的内存的总量。 对象的每个引用变量会占用 32 或 64bit(取决于操作系统),每个 Integer 需要占用 4byte,每个 Long 需要占用 8byte,诸如此类的其他信息可以自行查询。 Shallowheap 的值可能是经过了调整的(比如对齐到 8,具体取决于 Heap Dump 文件的格式), 以便更好地模拟虚拟机的真实消费情况。
对象 X 的 Retained Set 指的是一旦 X 被垃圾回收后也会随之被 GC 回收掉的对象的集合。对象 X 的 retained heap 指的是 X 的 retained set 中所有对象的 shallow heap 之和,或者说是因为对象 X而保持 alive 的内存的大小。
通常来说, shallow heap 就是对象自身在堆内存中的大小, 而同一个对象的 retained heap 指的是该对象被垃圾回收后释放的堆内存的大小。
这里看到最大的那个占用内存的对象,对象名称,Shallow Size也就是本身在堆内存中8B并不大,但是Retained Size有39M,包含的引用对象很多。
鼠标不悬浮会置空显示,我们左键单击固定在这个视图,还可以看到一些菜单。
可以看到中间下面的部分是一些MAT的功能,有
1. Histogram可以列出内存中的对象,对象的个数以及大小。
2. Dominator Tree可以列出那个线程,以及线程下面的那些对象占用的空间。
3.Top consumers通过图形列出最大的object。
4.Leak Suspects通过MA自动分析泄漏的原因。
Histogram
点开Histogram,点击Shallow Heap或Retained Heap排序,可以看见前排占用大量空间的有哪些
如果想看这个具体有哪些对象,可以点击这个右键—》show objects by classby outgoing Reference
PS:
简言之, Incomming Reference 指的是引用当前对象的外部对象; Outgoing Reference 指的是当前对象引用的外部对象。
对象的 incomming reference 保证对象处于 alive 从而免于被垃圾回收掉。
Outgoing reference 则展示了对象的具体内容, 有助于我们发现对象的用处。
比如可以看到int[]这个对象本身就很大,它的引用外部对象很小,说明它的内存主要是由于本身定义的过大引起的。
第二个对象就是由于引用外部对象过多引起的。
Dominator Tree
可以发现cachePainter和awt占用了很大的内存空间
Dominator Tree 展示了 Heap Dump 中最大的几个对象。 如果 dominator tree 中对象的父节点被移除的话那么, 那么相应对象及其后代节点也面临被回收的状态。
如果想探究一个对象持有了哪些对象并使之处于 alive, Dominator Tree 会是个很有用的工具。 此外还可以在 Dominator Tree 上按照 classloader 或 package 进行分组, 从而简化分析的过程.
可以点击左边你的三角展开查看持有的alive对象
Top Consumers
占用内存最大的是cache painter和awt,一并被分析出来的有8个需要关注的内存最大的对象
这一部分类似Overview那块,点击可以显示对象具体细节,比如有哪些字段啊,大小多少啊,值多少啊,可以点击第一个去看他的字段只有一个static类型的,本身并不大
Top Consumer 页按照类、 类加载器和包也分别提供了对应的类似图表信息。以下:
类:
这一步分展示了最高的Dominator Classes的Overview。从属的加载器
加载器:
包:
Leak Suspects
通过前面简单的了解,我们大致了解了什么地方的内存比较占用高,最后这个报告是Mat帮我们分析的可能怀疑内存泄露的地方
现在怀疑有两个问题(深色区域)
通过Leak Suspects的Problem Suspect 1点击【Details »】,
如下图如下图所示的上下文菜单中选择 List objects -> with outgoning references, 查看ThreadLocal都应用了些什么对象。
现在看到引用的对象如下图:
是cache Map对象