内存泄露之排查篇

标签: android内存泄露内存heap
747人阅读 评论(0) 收藏 举报
分类:

转载请标明出处:http://blog.csdn.net/xx326664162/article/details/49949833 文章出自:薛瑄的博客

你也可以查看我的其他同类文章,也会让你有一定的收货!

Android Device Monitor分析heap

Android Device Monitor分析heap的总内存占用大小来初步判断是否存在泄露

  Android Device Monitor,类似于eclipse的DDMS
  1. 在Devices 中,点击要监控的程序。
  2. 点击Devices视图界面中最上方一排图标中的“Update Heap”
  3. 点击Heap视图
  4. 点击Heap视图中的“Cause GC”按钮
  5. 到此为止需检测的进程就可以被监视。

这里写图片描述

Heap视图中部有一个Type叫做data object,即数据对象,也就是我们的程序中大量存在的类类型的对象。在data object一行中有一列是“Total Size”,其值就是当前进程中所有Java数据对象的内存总量,一般情况下,这个值的大小决定了是否会有内存泄漏。

可以这样判断:
进入某应用,不断的操作该应用,同时注意观察data object的Total Size值,正常情况下Total Size值都会稳定在一个有限的范围内,也就是说由于程序中的的代码良好,没有造成对象不被垃圾回收的情况。

所以说虽然我们不断的操作会不断的生成很多对象,而在虚拟机不断的进行GC的过程中,这些对象都被回收了,内存占用量会会落到一个稳定的水平;反之如果代码中存在没有释放对象引用的情况,则data object的Total Size值在每次GC后不会有明显的回落。随着操作次数的增多Total Size的值会越来越大,直到到达一个上限后导致进程被杀掉。

MAT分析hprof来定位内存泄露的原因所在

要调试内存,首先需要获取HPROF文件,HPROF文件是MAT能识别的文件,HPROF文件存储的是特定时间点,java进程的内存快照。有不同的格式来存储这些数据,总的来说包含了快照被触发时java对象和类在heap中的情况。由于快照只是一瞬间的事情,所以heap dump中无法包含一个对象在何时、何地(哪个方法中)被分配这样的信息。

1、使用Android Studio获取HPROF文件(两种方法)

第一种:使用Android Studio同样可以导出对应的HPROF文件:

这里写图片描述

最新版本的Android Studio得在文件上右键转换成标准的HPROF文件,才可以在MAT中打开。

第二种:打开Android Device Monitor,类似于eclipse的DDMS

这里写图片描述
(我这里使用别人的DDMS图,和在Android Device Monitor的操作一样)

选择存储路径保存后就可以得到对应进程的HPROF文件。

  • 如果是用 MAT Eclipse 插件获取的 Dump文件,不需要经过转换则可在MAT中打开,Adt会自动进行转换。

  • Android Studio需独立安装的MAT,并使用Android SDK自带的工具(hprof-conv 位置在sdk/platform-tools/hprof-conv)进行转换

 hprof-conv xxx.xxx.xxx.hprof xxx.xxx.xxx.hprof 

转换过后的.hprof文件即可使用MAT工具打开了。

2、Android Studio的同学使用MAT独立软件打开

3、查询内存泄露的地方

第一种方式:

1、在Histogram图中,在如图的位置输入进行查询,如:activity
选择with incominng references ,分析持有此类对象引用的外部对象

这里写图片描述
2、选择with incoming references 进入下图,分析这些持有引用的对象的GC路径,图中子菜单的两个选项,表示去除Phantom Ref(虚引用)和Weak Ref(弱引用),原因参考这里

这里写图片描述

3、逐个分析每个对象的GC路径是否正常
这里写图片描述

从这个路径可以看出是一个antiRadiationUtil工具类对象持有了MainActivity的引用导致MainActivity无法释放。此时就要进入代码分析此时antiRadiationUtil的引用持有是否合理(如果antiRadiationUtil持有了MainActivity的context导致节目退出后MainActivity无法销毁,那一般都属于内存泄露了)。

第二种方式:

怀疑某个对象存在泄露后,可以通过OQL来进一步证明。OQL可以通过查询语法,来查询具体的对象信息,主要使用的是查询某个类的实例信息。
语法为:

select * from instanceof Class
例如,查询类com.yunos.tv.launchersdk.view.component.ScreenContainer的所有实例:     
select * from instanceof com.yunos.tv.launchersdk.view.component.ScreenContainer

得到的结果如图:

这里写图片描述

Class Name Shallow Heap Retained Heap
com.yunos.tv.launchersdk.view.component.ScreenContainer @ 0x443108e8 680 2,712
com.yunos.tv.launchersdk.view.component.ScreenContainer @ 0x42817648 680 16,289,472

图中说明com.yunos.tv.launchersdk.view.component.ScreenContainer这个类有两个实例,两个实例占用的内存大小分别为2,712和16,289,472。
如过实例的数量超出预期,说明存在内存泄露,如果实例所占内存的大小超出预期,说明这个实例内部的引用存在问题,可以进一步分析这个实例的具体信息。

MAT对比操作前后的hprof来定位内存泄露的根因所在

为查找内存泄漏,通常需要两个 Dump结果作对比,打开 Navigator History面板,将两个表的 Histogram结果都添加到 Compare Basket中去

1、第一个HPROF 文件(usingFile > Open Heap Dump ).

2、打开Histogram view.

3、在NavigationHistory view里 (如果看不到就从Window >show view>MAT- Navigation History ), 右击histogram然后选择Add to Compare Basket .

这里写图片描述

4、打开第二个HPROF 文件然后重做步骤2和3.

5、切换到Compare Basket view, 然后点击Compare the Results (视图右上角的红色”!”图标)。

这里写图片描述

6、分析对比结果

这里写图片描述

可以看出两个hprof的数据对象对比结果。
通过这种方式可以快速定位到操作前后所持有的对象增量,从而进一步定位出当前操作导致内存泄露的具体原因是泄露了什么数据对象。

转载:
https://mp.weixin.qq.com/s?__biz=MzA3NTYzODYzMg==&mid=400891536&idx=1&sn=0b6c629b0abe4a359d6552cd244c0c0c&scene=1&srcid=0303pbuNmzzdPnwQLozLrMip&pass_ticket=8HY76%2FaZXUVizdmMUJA7KW40UY8GIW54Sj85H1PLcNuzGxmipJ36D7AsqXOA%2BdRb#rd
http://www.jianshu.com/p/d8e247b1e7b2#

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:607602次
    • 积分:8028
    • 等级:
    • 排名:第2581名
    • 原创:173篇
    • 转载:134篇
    • 译文:0篇
    • 评论:202条
    博客专栏
    最新评论
    有问题,联系我