EclipseMemoryAnalyzer的使⽤教程最实⽤
原⽂出处:郭霖,
Eclipse Memory Analyzer(MAT)是⼀款内存分析⼯具,
这个⼯具分为Eclipse插件版和独⽴版两种,如果你是使⽤Eclipse开发的,那么可以使⽤插件版MAT,⾮常⽅便。如果你是使⽤Android Studio开发的,那么就只能使⽤独⽴版的MAT了
下载好了之后下⾯我们开始学习如何去分析内存泄露的原因,⾸先还是进⼊到DDMS界⾯,然后在左侧⾯板选中我们要观察的应⽤程序进程,接着点击Dump HPROF file按钮,如下图所⽰:
点击这个按钮之后需要等待⼀段时间,然后会⽣成⼀个HPROF⽂件,这个⽂件记录着我们应⽤程序内部的所有数据。但是⽬前MAT还是⽆法打开这个⽂件的,我们还需要将这个HPROF⽂件从Dalvik格式转换成J2SE格式,使⽤hprof-conv命令就可以完成转换⼯作,如下所⽰:
hprof-conv dump.hprof converted-dump.hprof
为什么eclipse无法安装1
hprof-conv命令⽂件存放于/platform-tools⽬录下⾯。另外如果你是使⽤的插件版的MAT,也可以直接在Eclipse中打开⽣成的HPROF⽂件,不⽤经过格式转换这⼀步。
好的,接下来我们就可以来尝试使⽤MAT⼯具去分析内存泄漏的原因了,这⾥需要提醒⼤家的是,MAT并不会准确地告诉我们哪⾥发⽣了内存泄漏,⽽是会提供⼀⼤堆的数据和线索,我们需要⾃⼰去分析这些数据来去判断到底是不是真的发⽣了内存泄漏。那么现在运⾏MAT⼯具,然后选择打开转换过后的converted-dump.hprof⽂件,如下图所⽰:
MAT中提供了⾮常多的功能,这⾥我们只要学习⼏个最常⽤的就可以了。上图最中央的那个饼状图展⽰了最⼤的⼏个对象所占内存的⽐例,这张图中提供的内容并不多,我们可以忽略它。在这个饼状图的下⽅就有⼏个⾮常有⽤的⼯具了,我们来学习⼀下。
Histogram可以列出内存中每个对象的名字、数量以及⼤⼩。
Dominator Tree会将所有内存中的对象按⼤⼩进⾏排序,并且我们可以分析对象之间的引⽤结构。
⼀般最常⽤的就是以上两个功能了,那么我们先从Dominator Tree开始学起。
现在点击Dominator Tree,结果如下图所⽰:
这张图包含的信息⾮常多,我来带着⼤家⼀起解析⼀下。⾸先Retained Heap表⽰这个对象以及它所持有的其它引⽤(包括直接和间接)所占的总内存,因此从上图中看,前两⾏的Retained Heap是最⼤的,我们分析内存泄漏时,内存最⼤的对象也是最应该去怀疑的。
另外⼤家应该可以注意到,在每⼀⾏的最左边都有⼀个⽂件型的图标,这些图标有的左下⾓带有⼀个红⾊的点,有的则没有。带有红点的对象就表⽰是可以被GC Roots访问到的,根据上⾯的讲解,可以被GC Root访问到的对象都是⽆法被回收的。那么这就说明所有带红⾊的对象都是泄漏的对象吗?当然不是,因为有些对象系统需要⼀直使⽤,本来就不应该被回收。我们可以注意到,上图当中所有带红点的对象最右边都有写⼀个System Class,说明这是⼀个由系统管理的对象,并不是由我们⾃⼰创建并导致内存泄漏的对象。
那么上图中就⽆法看出内存泄漏的原因了吗?确实,内存泄漏本来就不是这么容易出的,我们还需要
进⼀步进⾏分析。上图当中,除了带有System Class的⾏之外,最⼤的就是第⼆⾏的Bitmap对象了,虽然Bitmap对象现在不能被GC Roots访问到,但不代表着Bitmap所持有的其它引⽤也不会被GC Roots访问到。现在我们可以对着第⼆⾏点击右键 -> Path to GC Roots -> exclude weak references,为什么选择exclude weak references呢?因为弱引⽤是不会阻⽌对象被垃圾回收器回收的,所以我们这⾥直接把它排除掉,结果如下图所⽰:
可以看到,Bitmap对象经过层层引⽤之后,到了MainActivity$LeakClass这个对象,然后在图标的左下⾓有个红⾊的图标,就说明在这⾥可以被GC Roots访问到了,并且这是由我们⾃⼰创建的Thread,并不是System Class了,那么由于MainActivity$LeakClass能被GC Roots访问到导致不能被回收,导致它所持有的其它引⽤也⽆法被回收了,包括MainActivity,也包括MainActivity中所包含的图⽚。
通过这种⽅式,我们就成功地将内存泄漏的原因出来了。这是Dominator Tree中⽐较常⽤的⼀种分析
⽅式,即搜索⼤内存对象通向GC Roots的路径,因为内存占⽤越⾼的对象越值得怀疑。
接下来我们再来学习⼀下Histogram的⽤法,回到Overview界⾯,点击Histogram,结果如下图所⽰:
这⾥是把当前应⽤程序中所有的对象的名字、数量和⼤⼩全部都列出来了,需要注意的是,这⾥的对象都是只有Shallow Heap⽽没有Retained Heap的,那么Shallow Heap⼜是什么意思呢?就是当前对象⾃⼰所占内存的⼤⼩,不包含引⽤关系的,⽐如说上图当中,byte[]对象的Shallow Heap最⾼,说明我们应⽤程序中⽤了很多byte[]类型的数据,⽐如说图⽚。可以通过右键 -> List objects -> with incoming references来查看具体是谁在使⽤这些byte[]。
那么通过Histogram⼜怎么去分析内存泄漏的原因呢?当然其实也可以⽤和Dominator Tree中⽐较相似的⽅式,即分析⼤内存的对象,⽐如上图中byte[]对象内存占⽤很⾼,我们通过分析byte[],最终也是能到内存泄漏所在的,但是这⾥我准备使⽤另外⼀种更适合Histogram的⽅式。⼤家可以看到,Histogram中是可以显⽰对象的数量的,那么⽐如说我们现在怀疑MainActivity中有可能存在内存泄漏,就可以在第⼀⾏的正则表达式框中搜索“MainActivity”,如下所⽰:
可以看到,这⾥将包含“MainActivity”字样的所有对象全部列出了出来,其中第⼀⾏就是MainActivity的实例。但是⼤家有没有注意到,当前内存中是有11个MainActivity的实例的,这太不正常了,通过情况下⼀个Activity应该只有⼀个实例才对。其实这些对象就是由于我们刚才不断地横竖屏切换所产⽣的,因为横竖屏切换⼀次,Activity就会经历⼀个重新创建的过程,但是由于LeakClass的存在,之前的Activity⼜⽆法被系统回收,那么就出现这种⼀个Activity存在多个实例的情况了。
接下来对着MainActivity右键 -> List objects -> with incoming references查看具体MainActivity实例,如下图所⽰:
如果想要查看内存泄漏的具体原因,可以对着任意⼀个MainActivity的实例右键 -> Path to GC Roots -> exclude weak references,结果如下图所⽰:
可以看到,我们再次到了内存泄漏的原因,是因为MainActivity$LeakClass对象所导致的。
好了,这⼤概就是MAT⼯具最常⽤的⼀些⽤法了,当然这⾥还要提醒⼤家⼀句,⼯具是死的,⼈是活的,MAT也没有办法保证⼀定可以将内存泄漏的原因出来,还是需要我们对程序的代码有⾜够多的了解,知道有哪些对象是存活的,以及它们存活的原因,然后再结合MAT给出的数据来进⾏具体的分析,这样才有可能把⼀些隐藏得很深的问题原因给出来。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论