使用MAT分析Java内存
Overview
MAT(Memory Analyzer Tool) 是一个JAVA Heaper分析器,可以用来分析内存泄露和减少内存消耗。分析Process showmap中的/dev/ashmem/dalvik-heap(deleted)一项所占用的Memory.可以参考我写的使用showmap分析系统内存占用情况一文。
下面就将一下如何使用Eclipse MAT分析Android应用程序内存的消耗。所需要的是已经安装ADT和SDK的Eclipse.然后可以在http://www.eclipse.org/mat/ 下载MAT插件将MAT安装在Eclipse上。
如下图所示,手机连接电脑,打开Eclipse,进入DDMS中,选择一个进程,可以看到下面的
画面:
update Heap键的作用是立即更新,使工具可以获得手机上运行的Android应用程序的最新Heap分配状况。dump Hprof键则可以立即dump Hprof文件(Java Heap 分配信息存储在Hprof文件中)。 Cause GC键主要就是强制引发一次GC(垃圾回收)。
点击dump Heap键,我们会看到如下画面:
这个就是Eclipse中Hprof文件分析界面的主页面了。
其中Histogram可以看到所有实例的分配情况, Dominator Tree列出了堆的最大对象。 Leak Suspects主要是列出怀疑的内存泄露处。
Histogram
首先,我们来看一下Histogram,
这个列出了所有实例类型,右键选中实例类型Byte,选择Merge Shortest Paths to GC Root,然后选择excluse all phantom/weak/soft etc refereneces. Merge Shortest Paths to GC Root主要显示最短离GC Root的路径。Java的垃圾回收机制简单来说有点类似树的深度遍历方式,如果一个对象有引用,则GC Root到这个对象之间是有路径可达的。如果GC Root到 这个对象之间无任何路径可达,则这个对象是不可触及的,是可以回收的。exclude all phantom/weaker/soft etc references则是排除虚引用,弱引用及软引用。因为这些引用一般是可以回收的。 (详细解释请参考深入Java虚拟机 垃圾回收一章)。
然后可以可以看到如下画面:
其中可以看到Resources类中有个sPreloadedDrawables的LongSparseArray对象,sPreloadedDrawables中有个mValues的Object数组,数组第139个个元素是一个NiePatchDrawable的对象,这个对象有个mNinePatch的对象,mNinePatch则有一个mChunk的Byte数组的引用。
可能大家已经注意到图中有个Shallow heap和Retained Heap, 具体代表什么意思呢?简单来讲,Shallow Heap Size是对象自身占用的Size。 Retained Heap Size是对象自身的Shallow Size +对象直接引用或者间接引用的对象的Shallow Size。
然后结合代码可以分析出来这个Byte数组是如何引用的,以及这个Byte数组是什么时候创建和销毁的,其创建和销毁是否是合理的。
假如说上面对象此时本来应该是被GC掉的,那么我们应该如何处理了。简单的办法就是将其中的某处置为null或者remove掉,使其到GC Root无路径可达,处于不可触及状态,垃圾回收器就可以回收了。
由于有很多对象,为了分析方便,我们可以点击Cause GC键使其强制发生一次GC,这样可以减少对象的个数,便于我们分析。
Leak Suspects
Leak Suspects列出了工具怀疑的内存泄露点。
在下图中,MAT工具怀疑第一个问题有1.5M的内存泄露:
然后接着,是问题一的描述,列出了一些比较大的实例。
点击Details可以看到细节信息。
不过工具怀疑的也未必真的是存在的,但提供了一种参考。
参考:http://help.eclipse.org/kepler/index.jsp?topic=/org.eclipse.mat.ui.help/welcome.html
http://www.eclipse.org/mat/about/screenshots.php
http://plumbr.eu/blog/how-much-memory-do-i-need-part-2-what-is-shallow-heap