背景
文件管理器App大量使用了Bitmap和数据缓存,虽然小心翼翼做了内存管理,但是还是可能出现内存泄露,通过代码分析来排查泄露工作量大可靠性也不够,所以这个时候需要借助工具来分析。
什么是内存泄露?
一些对象有着有限的生命周期。当这些对象所要做的事情完成了,我们希望他们会被回收掉。但是如果有一系列对这个对象的引用,那么在我们期待这个对象生命周期结束的时候被收回的时候,它是不会被回收的。它还会占用内存,这就造成了内存泄露。持续累加,内存很快被耗尽。比如,当 Activity.onDestroy 被调用之后,activity 以及它涉及到的 view 和相关的 bitmap 都应该被回收。但是,如果有一个后台线程持有这个 activity 的引用,那么 activity 对应的内存就不能被回收。这最终将会导致内存耗尽,然后因为 OOM 而 crash。
MAT分析大法
MAT分析是最常用的内存分析方法,通过查看堆引用排查内存泄露问题,使用步骤:
1、在内存泄露时,Dump Heap文件;
2、使用MAT工具查看Heap文件,分析本该回收未回收的对象;
3、分析GC Root中对象引用的最短引用路径;
4、找出引用中不该引用的对象,并修复;
以上内存分析方式需要对内存引用关系非常熟悉,并且具备一定内存分析基础才能有效解决内存泄露问题。如果有个库可以做完分析工作,开发只需要对内存泄露进行修复,岂不是剩下很多工作?
LeakCanary
LeakCanary 是一个在 debug build中用于检测内存泄露的开源 Java 库。当检测到内存泄露时,会界面通知或者日志提示,内存泄露检测全自动化。LeakCanary使用的代码简单,以Eclipse代码库为例如下:
导入LeakLibrary库到Eclipse并选择为Library工程(https://github.com/teffy/LeakcanarySample-Eclipse.git):

文管项目增加LeakCanary库工程依赖:

Application在OnCreate时初始化LeakCanary即可:
public class FunApplication extends Application{
public void onCreate() {
....
LeakCanary.install(this)
}
LeakCanary内存泄露分析和UI通知需要自己的Activity,因此需要在AndroidMenifest.xml中增加Activity声明:
<service
android:name="com.squareup.leakcanary.internal.HeapAnalyzerService"
android:enabled="false"
android:process=":leakcanary" />
<service
android:name="com.squareup.leakcanary.internal.DisplayLeakService"
android:enabled="false"/>
<activity
android:name="com.squareup.leakcanary.internal.DisplayLeakActivity"
android:icon="@drawable/__leak_canary_icon"
android:label="@string/__leak_canary_display_activity_label"
android:taskAffinity="com.squareup.leakcanary"
android:enabled="false"
android:theme="@style/__LeakCanary.Base" >
<intent-filter >
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
至此LeakCanary便布置成功。
测试LeakCanary
为了测试效果,现创建一个内存泄露示例,查看LeakCanary结果。在BaseSubActivity onCreate中开启一个线程并25s后运行完毕,进入设备页并退出,查看到结果:


可以看出LeakCanary可以给出具体泄露的UI和对应的变量!
网友评论