使用MAT分析内存泄露步骤

项目优化过程中,总会遇到内存的一些问题,即便前期设计很优秀,可有可能在编码过程中留下内存泄露等问题,而一般查找内存问题是比较困难的,而使用MAT工具,结合项目代码及个人经验,能够比较快速的定位问题并解决,下文就记录一下一般步骤,方便以后查找使用。

 

Native层内存分析

内存泄露的原因很多,如果是Android程序,内存一般分为native层和java层,用MAT主要是分析java层得内存使用情况。Native层得使用情况可以adb shell 后,输入指令 dumpsys meminfo 包名来查看,如下图:

 

使用MAT分析内存泄露步骤_第1张图片

其中Native所指就是Native层内存,其中size是是需要的内存(峰值)Allocated 是分配了的内存(实际占用)Dalvik 就是java层的内存。当nativedavik总数也就是total超过 单个程序内存的最大限制(16M/24M)时,OOM就很可能会出现。Native层的内存泄露查询需要根据操作步骤来不断查看内存情况,之后根据出问题的步骤,回到代码定位问题所在。

 

Dalvik层内存分析

Dalvik层则有两种方法定位,GC逐步定位是第一种

一种类似Native方法,在DDMS界面选中要分析的进程,点击update heap按钮,如下图:

使用MAT分析内存泄露步骤_第2张图片

箭头所指就是update heap按钮,点击后,在进程后面会出现蓝色图标(方框所示),这时点击Cause GC按钮(圆框所示),在Heap界面就会显示出Dalvik内存的使用情况,如下图:

使用MAT分析内存泄露步骤_第3张图片

之后根据操作不同,观察数据变化,根据操作步骤定位代码问题。

 

第二种就是使用MAT工具。

1.安装MAT,网上介绍两种方法,单机版和Eclipse打包版,如果你已经安装了ADT,里面就已经打包安装了MAT。这里以Eclipse打包为例讲解。

2.依然是点击update heap按钮,之后点击Dump HPROF file按钮(update heap按钮旁边的按钮)Eclipse默认是保存hprof文件到本地,可以在windows->preferences->Android->DDMS->HPROF Action:选择open in Eclipse。不过建议还是保存到自己指定位置,方便管理。

3.cmd,执行命令 hprof-conv xx.hprof oo.hprof;这是因为保存的hprof文件是二进制的,需要使用hprof-conv工具转换一下,hprof-conv工具在Android SDK的tools文件夹下。

4.在Eclipse中打开刚才转换后的hprof文件,如下图所示:

使用MAT分析内存泄露步骤_第4张图片

上面的饼图很直观的说明了点击按钮的瞬间,内存的使用情况。

5.点击Leak Suspects;这个是MAT帮你分析的内存可能存在问题的地方。如下图所示:

使用MAT分析内存泄露步骤_第5张图片

a,b是两个有内存问题的部分,c为正常部分,下面MAT也给出了初步的推测

6.点击Detail可以进入详情页查看具体的分析,如下图所示:

使用MAT分析内存泄露步骤_第6张图片

shortest paths to the Accumulation Point:从根元素到内存消耗聚集点的最短路径,上图中的根元素是java.lang.object的一个实例对象,内存消耗点是android.content.res.Resources的class对象。

Accumulated Objects:内存消耗聚集对象信息。由上图可知,android.content.res.Resources包含了一个android.util.LongSparseArray对象,而LongSparseArray对象包含了一个java.lang.object对象。

7.点击java.lang.Object[509]@0x40ddd228 对象->list objects->with outgoing references,弹出如下图所示界面:

使用MAT分析内存泄露步骤_第7张图片

我们可以看到Object对象中包含的都是BitmapDrawable和NinePathDrawable类型的元素;查找问题的源代码,根据提示,回到程序中,查找哪里大量使用了图片资源,在本程序中发现是图片缓存中保存了大量的图片,导致内存升高;问题定位到后,根据业务情况制定方案解决即可。

 

内存文件对比发现泄漏对象方法 

 上面的方法是根据MAT给出的怀疑点逐步分析,但是因为导出的内存文件是某一时刻的内存快照,所以分析起来可能不能很好的定位内存增长的点,于是就有了下面的内存文件对比发现泄漏对象的方法。

例如,一开始打开程序,导出一份hprof文件,反复操作一会后,在导出一份hprof文件,比较两个内存文件中的对象数和占用大小是否增加,如果增加比较明显,说明有内存一直没有释放,则有内存泄露嫌疑。以下是步骤说明:

1.打开第一个hprof文件,打开Histogram View(Window->Show View->Navigation History)

2.点击Create histogram按钮,在Navigation History中的histogram上点击右键,选择Add to Compare Basket,如下图所示:

使用MAT分析内存泄露步骤_第8张图片

3.再打开第二个hprof文件,重复第二步;

4.切换到Compare Basket窗口,点击Compare the results按钮(视图右上角的红色"!"图标)

5. 内存对比图如下所示:

使用MAT分析内存泄露步骤_第9张图片

class name中可以天劫regex来过滤比较的对象。Object0和Object1代表文件1和文件2的对象个数。Shallow Heap0和Shallow Heap1代表文件1和文件2对象自身占用内存大小,单位为byte。

 通过对比,将明显增加的对象拎出来单独分析。

 

总结

内存泄露存在多种可能,本文介绍的方法还需要结合自身经验才能做到快速有效的定位问题,这里总结几个容易出问题的点

1.Activity的Context引用。

2.图片资源的大量持有。

3.View对象的大量持有。

4.static关键字滥用。

5.Cursor未关闭。

6.广播未反注册

7.i/o操作后未关闭。

在编码时就需要多关注这些点,在查找问题时,也可以先从这些点入手,不断积累经验,相信以后对内存的把握会越来越强。


你可能感兴趣的:(Android开发)