LeakCanary相关解析

Android开发中经常会出现OOM的情况,使用LeakCanary可以对于OOM进行检测与分析,那么这一篇就通过分析LeakCanary
的源码来看看是如何检测内存泄露的。

LeakCanary使用

gradle中添加依赖,如下

debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'

然后在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);
}

通过这样就实现了LeakCanary使用。

LeakCanary源码分析

上面使用的关键代码就是LeakCanary.install(this),来看看这里的源码

public static RefWatcher install(Application application) {
    return ((AndroidRefWatcherBuilder)refWatcher(application).listenerServiceClass(DisplayLeakService.class).excludedRefs(AndroidExcludedRefs.createAppDefaults().build())).buildAndInstall();
}


public RefWatcher buildAndInstall() {
     RefWatcher refWatcher = this.build();
     if(refWatcher != RefWatcher.DISABLED) {
         LeakCanary.enableDisplayLeakActivity(this.context);
         ActivityRefWatcher.install((Application)this.context, refWatcher);
     }

     return refWatcher;
 }

这里其实是调用了AndroidRefWatcherBuilder类中的buildAndInstall方法,这里首先是生成了一个RefWatcher,接下来把这个对象与提供的pplication传入到
ActivityRefWatcher.install方法,我们去看这个方法,如下

public static void install(Application application, RefWatcher refWatcher) {
    (new ActivityRefWatcher(application, refWatcher)).watchActivities();
}

public void watchActivities() {
    this.stopWatchingActivities();
    this.application.registerActivityLifecycleCallbacks(this.lifecycleCallbacks);
}

这里主要调用了watchActivities方法,而这个方法里面则是向application里注册了一个ActivitylifecycleCallbacks的回调函数,可以用来监听Application整个生命周期所有Activity的lifecycle事件

接下来我们看一下LeakCanary中提供的这个lifecycleCallbacks,如下

private final ActivityLifecycleCallbacks lifecycleCallbacks = new ActivityLifecycleCallbacks() {
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    }

    public void onActivityStarted(Activity activity) {
    }

    public void onActivityResumed(Activity activity) {
    }

    public void onActivityPaused(Activity activity) {
    }

    public void onActivityStopped(Activity activity) {
    }

    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    }

    public void onActivityDestroyed(Activity activity) {
        ActivityRefWatcher.this.onActivityDestroyed(activity);
    }
};

可以看到这里只是监听了所有Activity的onActivityDestroyed事件,当Activity被Destory时,调用ActivityRefWatcher.this.onActivityDestroyed(activity)函数。

接下来看一下这个ActivityRefWatcher中的onActivityDestroyed方法到底做了什么事情,源码如下

void onActivityDestroyed(Activity activity) {
    this.refWatcher.watch(activity);
}

这里调用了RefWatcher的watch方法,通过调用后,如下

private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
    this.watchExecutor.execute(new Retryable() {
        public Result run() {
            return RefWatcher.this.ensureGone(reference, watchStartNanoTime);
        }
    });
}

Result ensureGone(KeyedWeakReference reference, long watchStartNanoTime) {
    long gcStartNanoTime = System.nanoTime();
    long watchDurationMs = TimeUnit.NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
    this.removeWeaklyReachableReferences();
    if(this.debuggerControl.isDebuggerAttached()) {
        return Result.RETRY;
    } else if(this.gone(reference)) {
        return Result.DONE;
    } else {
        this.gcTrigger.runGc();
        this.removeWeaklyReachableReferences();
        if(!this.gone(reference)) {
            long startDumpHeap = System.nanoTime();
            long gcDurationMs = TimeUnit.NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
            File heapDumpFile = this.heapDumper.dumpHeap();
            if(heapDumpFile == HeapDumper.RETRY_LATER) {
                return Result.RETRY;
            }

            long heapDumpDurationMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
            this.heapdumpListener.analyze(new HeapDump(heapDumpFile, reference.key, reference.name, this.excludedRefs, watchDurationMs, gcDurationMs, heapDumpDurationMs));
        }

        return Result.DONE;
    }
}

我们主要看一下ensureGone中的内容

在一个 activity 传给 RefWatcher 时会创建一个唯一的key对应这个activity,该key存入一个集合retainedKeys中。也就是说,所有我们想要观测的activity对应的唯一key都会被放入retainedKeys集合中。

基于我们对ReferenceQueue的了解,只要把队列中所有的reference取出来,并把对应retainedKeys里的key移除,剩下的key对应的对象都没有被回收。

1.ensureGone 首先调用removeWeaklyReachableReferences把已被回收的对象的key从retainedKeys移除,剩下的key都是未被回收的对象;

2.if(gone(reference))用来判断某个reference的key是否仍在retainedKeys里,若不在,表示已回收,否则继续;

3.gcTrigger.runGc();手动出发GC立即把所有WeakReference引用的对象回收;

4.removeWeaklyReachableReferences();再次清理retainedKeys,如果该reference还在retainedKeys里(if(!gone(reference))),表示泄漏;

5.利用heapDumper把内存情况dump成文件,并调用heapdumpListener进行内存分析,进一步确认是否发生内存泄漏。

6.如果确认发生内存泄漏,调用DisplayLeakService发送通知。

到这里leakCanary对于内存泄露的检测分析流程就完成了。

关于ActivityLifecycleCallbacks

ActivityLifecycleCallbacks是Application中声明的一个内部接口,结构如下

public interface ActivityLifecycleCallbacks {
    void onActivityCreated(Activity activity, Bundle savedInstanceState);
    void onActivityStarted(Activity activity);
    void onActivityResumed(Activity activity);
    void onActivityPaused(Activity activity);
    void onActivityStopped(Activity activity);
    void onActivitySaveInstanceState(Activity activity, Bundle outState);
    void onActivityDestroyed(Activity activity);
}

Application提供有一个registerActivityLifecycleCallbacks()的方法,需要传入的参数就是这个ActivityLifecycleCallbacks接口,作用和你猜的没错,就是在你调用这个方法传入这个接口实现类后,系统会在每个Activity执行完对应的生命周期后都调用这个实现类中对应的方法。

另外registerActivityLifecycleCallbacks()内部是把ActivityLifecycleCallbacks加到一个集合中,所以ActivityLifecycleCallbacks可以添加多个

而且ActivityLifecycleCallbacks只是在项目初始化的时候被装到集合中,并不会初始化任何东西,直到真正Activity执行到相应的生命周期,才会执行ActivityLifecycleCallbacks中的操作

所有使用ActivityLifecycleCallbacks会使我们代码会更加有创造力,因为使用ActivityLifecycleCallbacks可以实现很多不同的功能,而且是优雅的实现

简单想了一下ActivityLifecycleCallbacks可以实现什么功能。

  • 关于BaseActiviy的封装
  • 关于一些通用需要注册绑定以及解绑和解注册的操作
  • 关于前后台状态的检测

等等。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,472评论 25 707
  • LeakCanary LeakCanary是Square公司开源的检测内存泄露的工具, 如果怀疑自己或者队友写的代...
    常强儿阅读 855评论 1 2
  • 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏大家都不陌生了,简单粗俗的讲,...
    宇宙只有巴掌大阅读 2,326评论 0 12
  • 一个人真正的平静下来认真的体察周围动静的状态,所有的声响的时候,会突然发现,那些称之为干扰身心的所谓的脆弱的东西,...
    悄然Edward阅读 308评论 4 9
  • 这要是俄国:不愧为战斗种族;印度:果然开挂;德国:机器人一般地执行时刻表;日本:自觉自律的民族才能保证准点运行;中...
    Maxdoit粗版社阅读 106评论 0 0