一篇文章教你搞定内存泄漏与排查流程——安卓性能优化( 三 )


6、内存泄漏检查与解决流程经过前面的一段理论,可能很多小伙伴都有些不耐烦了,现在便来真正的操作 。

温馨提示:理论是进阶中必要的支持,否则只是知其然而不知其所以然 。
(1)第一步:对待检测功能扫雷式操作
当我们需要检查一块模块,或是整个App哪个地方有内存泄漏时,有时会比较茫然,有些大海捞针的感觉,毕竟泄漏不是每个页面都会有,而且有时是一个功能才会导致泄漏,所以我们可以采取“扫雷式操作”,也就是在需要检查的页面和功能中随便先使用一番,举个例子:假设检查MainActivity泄漏情况,可以登录进入后,此时来到了MainActivity,后又登出,再次登录进入MainActivity 。
(2)第二步:借助 Android Profiler获得内存快照
使用Android Profiler的GC功能,强制进行垃圾回收,再dump下内存("Android Profiler功能简介"图的②按钮) 。然后等待一段时间,会出现图中红色框部分:
一篇文章教你搞定内存泄漏与排查流程——安卓性能优化

文章插图
 
在这里得到的页面,其实比较难直观获得内存分析的数据,最多只是选择“Arrange by package”按照包进行排序,然后进到自己的包下,查看应用内的activity的引用数是否正常,来判断其是否有正常回收
一篇文章教你搞定内存泄漏与排查流程——安卓性能优化

文章插图
 
图中列的说明
Alloc Cout : 对象数
Shallow Size : 对象占用内存大小
Retained Set : 对象引用组占用内存大小(包含了这个对象引用的其他对象)
(3)第三步:借助Android Studio分析
至此,我们还是没得到直观的内存分析数据,我们需要借助更专业的工具 。我们现将通过下图中红框内的按钮,将刚才的内存快照保存为hprof文件 。
 
一篇文章教你搞定内存泄漏与排查流程——安卓性能优化

文章插图
 
将保存好的hprof文件拖进AS中,勾选“Detect Leaked Activities”,然后点击绿色按钮进行分析 。
一篇文章教你搞定内存泄漏与排查流程——安卓性能优化

文章插图
 
如果有内存泄漏的话,会出现如下图的情况 。图中很清晰的可以看到,这里出现了MainActivity的泄漏 。并且观察到这个MainActivity可能不止一个对象存在,可能是我们上次退出程序的时候发生了泄漏,导致它不能回收 。而在此打开app,系统会创建新的MainActivity 。但至此我们只是知道MainActivity泄漏了,不知具体是哪里导致了MainActivity泄漏,所以需要借助MAT来进一步分析 。
一篇文章教你搞定内存泄漏与排查流程——安卓性能优化

文章插图
 
(4)第四步:hprof文件转换
在使用MAT打开hprof文件前先要对刚才保存的hprof文件进行转换 。通过终端,借助转换工具hprof-conv(在sdk/platform-tools/hprof-conv),使用命令行:
hprof-conv -z src dst-z:排除不是app的内存,比如Zygote
src:需要进行转换的hprof的文件路径
dst:转换后的文件路径(文件后缀还是.hprof)
(5)第五步:通过MAT进行具体分析 在MAT中打开转换了的hprof文件,如下图
一篇文章教你搞定内存泄漏与排查流程——安卓性能优化

文章插图
 
打开后会看到如下图!
我们需要进入到"Histogram"来分析,点击下图中的按钮
一篇文章教你搞定内存泄漏与排查流程——安卓性能优化

文章插图
 
打开"Histogram"后,会看到下图,在红框中输入在AS中观察到的泄漏的类,例如上面得知的MainActivity
一篇文章教你搞定内存泄漏与排查流程——安卓性能优化

文章插图
 
然后将搜索得到的结果进行合并,排除“软”、“弱”、“虚”引用对象,右键点击搜索到的结果,选择如下图的选项
一篇文章教你搞定内存泄漏与排查流程——安卓性能优化

文章插图
 
得到合并结果如下
 
一篇文章教你搞定内存泄漏与排查流程——安卓性能优化

文章插图
 
从分析结果可知,MainActivity是因为com.netease.nimlib.g.e中的一个hashMap持有导致,这里的e类是第三方库的类,显然已被混淆,造成泄漏无非两种可能,一种是第三方库的bug,一种是自己使用不当,例如忘记解绑操作等 。具体的打断这个持有需要按照自己的代码进行分析,实例中的问题是因为使用第三方库注册后,在退出页面没有进行注销导致的 。


推荐阅读