LeakCanary原理解析

转载注明出处: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在

  • 15
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值