转载注明出处:http://blog.csdn.net/xiaohanluo/article/details/78196755
使用
LeakCanary是Square为Android应用提供的一个监测内存泄露的工具,源码地址:https://github.com/square/leakcanary。
在gradle文件中引入依赖:
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
}
在项目的Application中添加检测:
public class ExampleApplication extends Application {
@Override public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
// Normal app init code...
}
}
如果检测到有内存泄漏,手机桌面会多出一个图标,点进去查看可以看见泄漏信息。
图-1 内存泄漏示意图
检测原理
监听
在Android中,当一个Activity
走完onDestroy
生命周期后,说明该页面已经被销毁了,应该被系统GC回收。通过Application.registerActivityLifecycleCallbacks()
方法注册Activity
生命周期的监听,每当一个Activity
页面销毁时候,获取到这个Activity
去检测这个Activity
是否真的被系统GC。
检测
当获取了待分析的对象后,需要确定这个对象是否产生了内存泄漏。
通过WeakReference
+ ReferenceQueue
来判断对象是否被系统GC回收,WeakReference 创建时,可以传入一个 ReferenceQueue 对象。当被 WeakReference 引用的对象的生命周期结束,一旦被 GC 检查到,GC 将会把该对象添加到 ReferenceQueue 中,待ReferenceQueue处理。当 GC 过后对象一直不被加入 ReferenceQueue,它可能存在内存泄漏。
当我们初步确定待分析对象未被GC回收时候,手动触发GC,二次确认。
分析
分析这块使用了Square的另一个开源库haha,https://github.com/square/haha,利用它获取当前内存中的heap堆信息的快照snapshot,然后通过待分析对象去snapshot里面去查找强引用关系。
源码分析
检测过程主要分为两个部分
- 监听Activity销毁,并判断是否存在内存泄漏
- 找到内存泄漏的对象的引用路径
监听
直接从LeakCanary.install()方法开始看。
/**
* Creates a {@link RefWatcher} that works out of the box, and starts watching activity
* references (on ICS+).
*/
public static RefWatcher install(Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
/**
* Builder to create a customized {@link RefWatcher} with appropriate Android defaults.
*/
public static AndroidRefWatcherBuilder refWatcher(Context context) {
return new AndroidRefWatcherBuilder(context);
}
install()
方法中首先实例化了一个AndroidRefWatcherBuilder
类。
然后使用listenerServiceClass()
方法设置了DisplayLeakService
类,这个类用于分析内存泄漏结果信息,然后发送通知给用户。
public final class AndroidRefWatcherBuilder extends RefWatcherBuilder<AndroidRefWatcherBuilder> {
...
/**
* Sets a custom {@link AbstractAnalysisResultService} to listen to analysis results. This
* overrides any call to {@link #heapDumpListener(HeapDump.Listener)}.
*/
public AndroidRefWatcherBuilder listenerServiceClass(
Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
return heapDumpListener(new ServiceHeapDumpListener(context, listenerServiceClass));
}
...
}
public class RefWatcherBuilder<T extends RefWatcherBuilder<T>> {
...
public final T heapDumpListener(HeapDump.Listener heapDumpListener) {
this.heapDumpListener = heapDumpListener;
return self();
}
...
}
然后调用excludedRefs()
方法设置添加一些白名单,通俗来讲就是不要误伤了友军。在AndroidExcludedRefs
类中以枚举的形式定义了忽略列表信息,如果这些列表中的类发生了内存泄漏,并不会显示出来,同时HeapAnalyzer在