简述

在性质优化中,内存是一个只好聊的话题;可是内存泄漏,展现已经变为内存优化的一个重量级的大势。当前风行的内存泄漏分析工具中,不得不提的就是LeakCanary框架;这是一个合龙方便,
使用便捷,配置顶尖简单的框架,实现的效率却是极为强大的。


怎么样是内存泄露

局部对象具备有限的生命周期。当这么些目标所要做的事体完了了,我们目的在于她们会被回收掉。但是假诺有一多级对那个目标的引用,那么在大家盼望这一个目标生命周期结束的时候被注销的时候,它是不会被回收的。它还会占有内存,这就招致了内存泄露。持续累加,内存很快被耗尽。

诸如,当 Activity.onDestroy被调用之后,activity 以及它事关到的 view
和血脉相通的 bitmap 都应有被回收。可是,如果有一个后台线程持有这么些 activity
的引用,那么 activity
对应的内存就不可能被回收。这最终将会造成内存耗尽,然后因为 OOM 而 crash。

不骗你,真的,使用就是如此简单 ?!

1. 你需要添加到布置的唯有这么些

dependencies {

debugCompile ‘com.squareup.leakcanary:leakcanary-android:1.3’

releaseCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.3’

}

2. 您早晚需要起先化一下,当然, 推荐在Application中

public class MyApplicationextends Application {

        @Override

        public void onCreate() {

                super.onCreate();

                LeakCanary.install(this);

                }

      }

3.
哪些?你还在下一步?已经截至了!通过上述配置,你就可以轻松使用LeakCanary检测内存泄漏了

   
关于LeakCanary的事无巨细使用教程,提出去看:LeakCanary粤语使用验证


聊天截至,我想你们来自然不是看自己这么些废话的,那么现在进来正题!本篇我们所想的,就是LeakCanary为何可以这样神奇,它是怎么检测内存泄漏的?上面我们解开谜题!


LeakCanary

LeakCanary
Square公司支付的一个用以检测OOM(out
of memory的缩写)问题的开源库。你可以在 debug 包种轻松检测内存泄露。
Github地址:https://github.com/square/leakcanary

《LeakCanary原理》  主题类分析 

01    LeakCanary                                        源码解析

02    LeakCanary   
                                    SDK提供类

03    DisplayLeakActivity  
                        内存泄漏的查看页面

04    HeapAnalyzerService                         内存堆分析服务,
为了保证App进程不会由此受影响变慢&内存溢出,运行于独立的经过

05    HeapAnalyzer  
                                  剖析由Ref沃特(Wat)cher生成的堆转储新闻,
验证内存泄漏是否实际存在

06    HeapDump  
                                       堆转储消息类,存储堆转储的相干音讯

07    ServiceHeapDumpListener  
             一个监听,包含了启封分析的不二法门

08    RefWatcher  
                                        主干类, 翻译自官方:
检测不可达引用(可能地),当发现不足达引用时,它会触发
 
                                                                       HeapDumper(堆音信转储)

09    ActivityRefWatcher 
                             Activity引用检测,
包含了Activity生命周期的监听执行与截至

透过以上列表,让我们对LeakCanary框架的重中之重类有个大致的垂询,并按照以上列表,对这多少个框架的大体效用有一个模糊的怀疑。


漫无目标的看源码,很容易迷失在荒漠的Code
Sea中,无论是看源码,仍旧接手外人的花色,都是这么;因而,带着题材与目的性来看那么些扑朔迷离的东西是很有必不可少的,也使得大家阅读效能大大提升;想要了然LeakCanary,我们最大的迷惑是怎么着,我列出来,看看是与你不约而同。

Question1:   
在Application中初叶化之后,它是哪些检测所有的Activity页面的 ?

Question2:    内存泄漏的判定条件是怎么 ?
检测内存泄漏的编制原理是何等?

Question3:    检测出内存泄漏后,它又是如何变迁泄漏音信的?
内存泄漏的出口轨迹是怎么得到的?

追思一下这一个框架,其实大家想领悟的机制不外乎三:

  1. 内存泄漏的检测机制

  2. 内存泄漏的论断机制

  3. 内存泄漏的轨道生成机制

俺们会在源码分析最终,依次回答上述的多少个问题,可能在阅读源码在此之前,大家先要对内存泄漏做一些基础概念与原理的知晓。


咋样是内存泄漏(MemoryLeak)?

世家对这几个概念应该不生疏吧,当我们使用一个Bitmap,使用到位后,没有recycle回收;当我们利用Handler,
在Activity销毁时不曾处理;当我们运用Cursor,最后没有close并置空;以上这些都会招致一定水准上的内存泄漏问题。那么,什么是内存泄漏?

内存泄漏(Memory
Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法自由,造成系统内存的荒废,导致程序运行速度放慢甚至系统崩溃等严重后果。

以上是百度宏观的表明,总括下为:内存泄漏是不采纳或用完的内存,因为一些原因无法回收,造成的一种内存浪费;内存泄漏的本来面目是内存浪费。以村办明白来分解,通俗一点就是

  1. GC回收的对象必须是眼下从不此外引用的靶子

2.当对象在应用形成后(对大家而言已经是废品对象了),
我们从未自由该目的的引用,导致GC不可能回收该对象而继续占有内存

3.污染源对象依然占据内存,那块内存空间便浪费了

内存泄漏与内存溢出的分别是如何?

从名称来看,一个外泄,一个溢出,其实很好精通。

内存泄漏
垃圾对象依旧占据内存,如水龙头的泄露,水自然是属于基本的,
不过水龙头没关紧,那么泄漏到了水池;再来看内存,内存本来应             
     
 该被回收,可是如故在内存堆中;总括一下就是内存存在于不该存在的地点(没用的地点)

内存溢出
内存占用达到最大值,当需要分配内存时,已经远非内存能够分配了,就是溢出;依然以水池为例,
水池的水一旦满了,那么一旦继                     
续需要从水龙头流水的话,水就会溢出。总括一下就是,内存的分配超出最大阀值,导致了一种特别

驾驭了彼此的概念,那么双方有咋样关联吧?

内存的溢出是内存分配达到了最大值,而内存泄漏是无用内存充斥了内存堆;由此内存泄漏是促成内存溢出的主犯之一,而且是很大的首恶;因为内存分配完后,哪怕占用再大,也会回收,而泄漏的内存则不然;当清理掉无用内存后,内存溢出的阀值也会相应回落。


JVM咋样判断一个目的是废品对象?

该问题也即垃圾对象搜索算法,JVM接纳图论的可达遍历算法来判定一个目的是否是垃圾对象,
如若对象A是可达的,则觉得该目的是被引述的,GC不会回收;如若目的A或者块B(几个目标引用组成的目标块)是不可达的,那么该对象或者块则判定是不可达的排泄物对象,GC会回收。


如上科普的两个小知识:1) 内存泄漏  2) JVM搜索算法
是读书LeakCanary源码的基本功,有助于源码的精通与记忆。好了,下面来看一下LeakCanary的源码,看看LeakCanary是怎么工作的吧!

既然LeakCanary的初步化是从install()开头的,那么从init开头看

追忆一下骨干类模块可知,内存分析模块是在单独进程中执行的,这么设计是为着保证内存分析过程不会对App进程造成消极的熏陶,如使App进程变慢或导致out
of Memory问题等。由此

首先步: 判断APP进程与内存分析过程是否属于同一进程;如假诺,
则再次回到空的Ref沃特(Wat)cher DISABLED;即使不是,往下走,看第二步

是不是与分析过程是同一个, isInAnalyzerProcess

与分析过程一致,再次来到一个空的DISABLED

第二步: enableDisplayLeakActivity 开启显示内存泄漏音讯的页面

调用了setEnabled,记住参数DisplayLeakActivity就是翻开泄漏的页面,enable传true,开启Activity组件

那多少个方法的效用是设置四大组件开启或剥夺,从上图传的参数看,是打开了查看内存泄漏的页面

其三步:开端化一个ServiceHeapDumpListener,这是一个敞开分析的接口实现类,类中定义了analyze方法,用于开启一个DisplayLeak瑟维斯(Service)服务,从名字就足以见到,这是一个体现内存泄漏的扶助劳动

看注释,这么些服务的功效是分析HeapDump,写入一个记录文件,并弹出一个Notification

第四步:起首化六个沃特cher, Ref沃特(Wat)cher和ActivityRef沃特(Wat)cher.
这多少个沃特(Wat)cher的功效分别为分析内存泄漏与监听Activity生命周期

ActivityRef沃特(Wat)cher监听Activity生命周期,在最先化时起先监听Activity生命周期(watchActivities)

watchActivities中注册了独具Activity的生命周期统一监听;onActiityDestroy会在onDestroy时实施,执行watch,检测内存泄漏

何以行使

引入LeakCanary库 ,在档次的build.gradle文件添加:

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

gradle 强大的可配置性,可以保证只在编译 debug
版本时才会检查内存泄露,而编译 release
等版本的时候则会活动跳过检查,制止影响属性。
在自定义的Application中先导化 ,LeakCanary.install()会回来一个预定义的
Ref沃特cher,同时也会启用一个 ActivityRef沃特cher,用于机动监控调用
Activity.onDestroy()之后泄的activity。

假诺只想检测Activity的内存泄露,只需要丰硕这一行代码 。

 private static RefWatcher refWatcher;
 @Override
    public void onCreate() {
        super.onCreate();
        //LeakCanary 就会自动侦测 activity 的内存泄露
        // 会返回一个预定义的 RefWatcher ,同时也会启用一个 ActivityRefWatcher,用于自动监控调用 Activity.onDestroy() 之后泄露的 activity。
        refWatcher = LeakCanary.install(this);
    }

万一还想检测fragment

public class BaseFragment extends Fragment {
    //使用 RefWatcher 监控 Fragment:
    @Override
    public void onDestroy() {
        super.onDestroy();
        RefWatcher refWatcher = MyApplication.getRefWatcher();
        refWatcher.watch(this);
    }
}

当你在测试debug版本过程中出现内存泄露时,LeakCanary将会自动突显一个公告栏

总统娱乐网址 1

screenshot.png

由此通知里的音讯,我们可以解决许多内存泄露问题 。

备注:LeakCanary只襄助4.0之上,原因是其中在watch
每个Activity时调用了Application的registerActivityLifecycleCallback函数,这些函数只在4.0上才支撑,不过在4.0之下也是足以用的,可以在Application将官重临的Ref沃特(Wat)cher存下来,然后在基类Activity的onDestroy函数中调用。

透过以上代码分析,我们得以汲取第一个问题的答案。LeakCanary通过ApplicationContext统一登记监听的章程,来监督所有的Activity生命周期,并在Activity的onDestroy时,执行Ref沃特cher的watch方法,该格局的功用就是检测本页面内是否存在内存泄漏问题。


下面我们延续来分析中央类Ref沃特cher中的源码,检测机制的为主逻辑便在Ref沃特(Wat)cher中;相信阅读完这多少个类后,第二个问题的答案便呼之欲出了。

既然想弄了解Ref沃特cher做了怎么,那么先来看一下法定的分解

监听可能不可达的引用,当Ref沃特(Wat)cher判定一个引用可能不足达后,会触发HeapDumper(堆转储)

从地点图能够看来官方的解释。
Ref沃特(Wat)cher是一个引用检测类,它会监听可能会晤世泄漏(不可达)的对象引用,如若发现该引用可能是泄漏,那么会将它的消息征集起来(HeapDumper).

从Ref沃特cher源码来看,主题措施首要有四个: watch()和 ensureGone()。假设大家想单独监听某块代码,如fragment或View等,大家需要手动去调用watch()来检测;因为下面讲过,默认的watch()仅执行于Activity的Destroy时。watch()是我们直接调用的法子,ensureGone()则是切实可行什么处理了,下边我们来看一下 

watch 检测主旨措施

上图为watch()的源码, 大家先来看一下合法的笺注

监听提供的引用,检查该引用是否可以被回收。这么些点子是非阻塞的,因为检测效率是在Executor中的异步线程执行的

从上述源码可以见到,watch里面只是实施了一定的预备干活,如判空(checkNotNull),
为各样引用生成一个唯一的key,
起首化KeyedWeakReference;关键代码仍旧在watchExecutor中异步执行。引用检测是在异步执行的,由此这些历程不会阻塞线程。

检测中央代码 gone()判定WeakReference中是否包含当前引用

上述是检测的主干代码实现,从源码可以见见,检测的流水线:

1) 移除不可达引用,倘若当前引用不设有了,则不继续执行

2) 手动触发GC操作,gcTrigger中封装了gc操作的代码 

3) 再一次移除不可达引用,如若引用不设有了,则不继续执行

4) 假使五遍判定都未曾被回收,则先导分析这些引用,末了生成HeapDump消息

总括一下规律:

1.
弱引用与ReferenceQueue联合利用,倘诺弱引用关联的目的被回收,则会把这一个弱引用参与到ReferenceQueue中;通过那一个原理,可以见见removeWeaklyReachableReferences()执行后,会对应除去KeyedWeakReference的数量。尽管这多少个引用继续存在,那么就表达没有被回收。

2.
为了确保最大担保的论断是否被回收,一共执行了三回回收判定,包括三次击动GC后的回收判定。一回都未曾被回收,很大程度上证实了这几个目的的内存被泄露了,但并无法100%担保;因而LeakCanary是存在极小程度的误差的。

下面的代码,总计下流程就是

判断是否回收(KeyedWeakReference是否留存该引用), Y -> 退出, N
-> 向下执行

手动触发GC

判定是否回收, Y -> 退出, N-> 向下实施

一次未被回收,则分析引用意况:

1) humpHeap :  这个办法是生成一个文书,来保存内存分析消息 

2) analyze: 执行分析

因此以上的代码分析,第二个问题的答案已经浮出水面了呢!


接下去分析内存泄漏轨迹的变更~

最后的调用,是在Ref沃特cher中的ensureGone()中的最后,如图

解析末了调用,在ensureGone()中

很彰着,走的是heapdumpListener中的analyze方法,继续追踪heapdumpListener是在LeakCanary先河化的时候起头化并传播Ref沃特cher的,如图

在install中初阶化并传播Ref沃特(Wat)cher

开拓进去Service(Service)HeapDumpListener,看中间实现,如图

ServiceHeapDumpListener中的analyze

调用了HeapAnalyzerService,在独立的历程中展开分析,如图 

HeapAnalyzerService(Service)分析进程

HeapAnalyzer瑟维斯(Service)中经过HeapAnalyzer来展开实际的分析,查看HeapAnalyzer源码,如图

HeapAnalyzer

举办剖析时,调用了openSnapshot方法,里面用到了SnapshotFactory

org.eclipse.mat

从上图可以见见,那些本子的LeakCanary采用了MAT对内存音信举办分析,并生成结果。其中在分析时,分为findLeakingReference与findLeakTrace来查找泄漏的引用与轨道,遵照GCRoot开始按树形结构依次提议当前引述的轨道音信。


透过上述分析,最终得出的结果为:

1. Activity检测机制是何许?

答:
通过application.registerActivityLifecycleCallbacks来绑定Activity生命周期的监听,从而监控所有Activity;
在Activity执行onDestroy时,起初检测当前页面是否存在内存泄漏,并分析结果。由此,假诺想要在不同的地点都需要检测是否存在内存泄漏,需要手动添加。

2. 内存泄漏检测机制是怎么样?

答:
KeyedWeakReference与ReferenceQueue联合使用,在弱引用关联的对象被回收后,会将引用添加到ReferenceQueue;清空后,可以遵照是否持续含有该引用来判断是否被回收;判定回收,
手动GC,
再度判定回收,拔取双重判定来担保当前引用是否被回收的事态不错;如若五次都未回收,则确定为泄漏对象。

3. 内存泄漏轨迹的变更过程 ?

答: 该版本拔取eclipse.Mat来分析泄漏详细,从GCRoot开端渐渐转移引用轨迹。

经过整篇著作分析,你还在疑惑么?

干活原理

简单概述一下, 源码还并未分析精通 。

  1. Ref沃特cher.watch()创制一个
    KeyedWeakReference
    到要被监控的目标 (也就是弱引用)。
  2. 下一场在后台线程检查引用是否被免去,要是没有,调用GC。
  3. 比方引用仍旧未被扫除,把 heap 内存 dump 到 APP
    对应的文件系统中的一个 .hprof文件中。
  4. 在此外一个历程中的 HeapAnalyzer瑟维斯(Service)有一个
    HeapAnalyzer使用HAHA
    解析这么些文件。得益于唯一的 reference key, HeapAnalyzer找到
    KeyedWeakReference,定位内存泄露。
  5. HeapAnalyzer计算 到 GC roots
    的最短强引用路径
    ,并规定是否是泄露。假倘诺的话,建立导致泄露的引用链。
  6. 引用链传递到 APP 进程中的 DisplayLeakService,
    并以通知的花样呈现出来。

源码层面简单解析

RefWatch

Reft沃特cher是leakcancay检测内存泄露的发起点。使用方法为,在对象生命周期即将收尾的时候,调用

    RefWatcher.watch(Object object)

为了达到检测内存泄露的目标,Ref沃特(Wat)cher需要

  private final Executor watchExecutor;
  private final DebuggerControl debuggerControl;
  private final GcTrigger gcTrigger;
  private final HeapDumper heapDumper;
  private final Set<String> retainedKeys;
  private final ReferenceQueue<Object> queue;
  private final HeapDump.Listener heapdumpListener;
  • watchExecutor: 执行内存泄露检测的executor
  • debuggerControl :用于查询是否正在调试中,调试中不会举行内存泄露检测
  • gcTrigger: 用于在认清内存泄露在此之前,再给三遍GC的空子
  • headDumper: 用于在爆发内存泄露室执行dump 内存heap
  • retainedKeys: 持有这多少个呆检测以及发生内存泄露的引用的key
  • queue : 用于判断弱引用所所有的目标是否已被GC。
  • heapdumpListener: 用于分析前边暴发的dump文件,找到内存泄露的案由
    接下去,大家来探望watch函数背后是哪些运用这多少个工具,生成内存泄露分析报告的。

 /**
   * Watches the provided references and checks if it can be GCed. This method is non blocking,
   * the check is done on the {@link Executor} this {@link RefWatcher} has been constructed with.
   *
   * @param referenceName An logical identifier for the watched object.
   */
  public void watch(Object watchedReference, String referenceName) {
    checkNotNull(watchedReference, "watchedReference");
    checkNotNull(referenceName, "referenceName");
    // 如果处于debug模式,直接return
    if (debuggerControl.isDebuggerAttached()) {
      return;
    }
    //记住开始观测的时间
    final long watchStartNanoTime = System.nanoTime();
    //生成一个随机的key,并加入set中
    String key = UUID.randomUUID().toString();
    retainedKeys.add(key);
    //生成一个KeyedWeakReference
    final KeyedWeakReference reference = new KeyedWeakReference(watchedReference, key, referenceName, queue);
     //调用watchExecutor,执行内存泄露的检测
    watchExecutor.execute(new Runnable() {
      @Override public void run() {
           ensureGone(reference, watchStartNanoTime);
       }
    });
  }

从而最后的主导函数是在ensureGone这一个法子里面。要领会其行事规律,就得从keyedWeakReference说起

WeakReference与ReferenceQueue

从watch函数中,可以看来,每一回检测对象内存是否泄漏时,大家都会生成一个KeyedReferenceQueue,这一个类其实就是一个WeakReference,只不过其额外顺带了一个key和一个name

/** @see {@link HeapDump#referenceKey}. */
final class KeyedWeakReference extends WeakReference<Object> {
  public final String key;
  public final String name;

  KeyedWeakReference(Object referent, String key, String name,
      ReferenceQueue<Object> referenceQueue) {
      super(checkNotNull(referent, "referent"), checkNotNull(referenceQueue, "referenceQueue"));
      this.key = checkNotNull(key, "key");
      this.name = checkNotNull(name, "name");
  }
}

在构造时大家需要传入一个ReferenceQueue,这么些ReferenceQueue是直接传入了WeakReference中,关于这几个类,有趣味的能够直接看Reference的源码。大家这里需要知道的是,每一次WeakReference所指向的目的被GC后,这一个弱引用都会被放入这个与之相关联的ReferenceQueue队列中。

在reference类加载的时候,java虚拟机会开创一个最大优先级的后台线程,这个线程的干活原理就是无休止检测pending是否为null,如若不为null,就将其放入ReferenceQueue中,pending不为null的境况就是,引用所针对的靶子已被GC,变为不可达。

这就是说只要我们在社团弱引用的时候指定了ReferenceQueue,每当弱引用所指向的对象被内存回收的时候,我们就可以在queue中找到这些引用。假若我们目的在于一个目的被回收,这即便在接下去的预期时间之后,大家发现它依然没有出现在ReferenceQueue中,这就可以判断它的内存泄露了。LeakCanary检测内存泄露的基本原理就在此地。

监测时机

何以时候去检测能判定内存泄露呢?这些可以看Android沃特chExecutor的落实

public final class AndroidWatchExecutor implements Executor {
  private final Handler backgroundHandler;

  public AndroidWatchExecutor() {
    mainHandler = new Handler(Looper.getMainLooper());
    HandlerThread handlerThread = new HandlerThread(LEAK_CANARY_THREAD_NAME);
    handlerThread.start();
    backgroundHandler = new Handler(handlerThread.getLooper());
  }
  ....
  private void executeDelayedAfterIdleUnsafe(final Runnable runnable) {
    // This needs to be called from the main thread.
    Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
      @Override public boolean queueIdle() {
         backgroundHandler.postDelayed(runnable, DELAY_MILLIS);
         return false;
      }
    });
  }
}

此间又来看一个相比少的用法,IdleHandler,IdleHandler的法则就是在messageQueue因为空闲等待信息时给使用者一个hook。那Android沃特(Wat)chExecutor会在主线程空闲的时候,派发一个后台任务,这多少个后台任务会在DELAY_MILLIS时间未来执行。LeakCanary设置的是5秒。

二次认同保证内存泄露准确性

为了制止因为gc不即刻带来的误判,leakcanay会举办二次确认举办管教。

void ensureGone(KeyedWeakReference reference, long watchStartNanoTime) {
    long gcStartNanoTime = System.nanoTime();
    //计算从调用watch到进行检测的时间段
    long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
    //根据queue移除已被GC的对象的弱引用
    removeWeaklyReachableReferences();
    //如果内存已被回收或者处于debug模式,直接返回
    if (gone(reference) || debuggerControl.isDebuggerAttached()) {
      return;
    }
    //如果内存依旧没被释放,则再给一次gc的机会
    gcTrigger.runGc();
    //再次移除
    removeWeaklyReachableReferences();
    if (!gone(reference)) {
      //走到这里,认为内存确实泄露了
      long startDumpHeap = System.nanoTime();
      long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);

      File heapDumpFile = heapDumper.dumpHeap();

      if (heapDumpFile == null) {
        // Could not dump the heap, abort.
        return;
      }
      long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
      heapdumpListener.analyze(
          new HeapDump(heapDumpFile, reference.key, reference.name, watchDurationMs, gcDurationMs,
              heapDumpDurationMs));
    }
  }

Dump Heap

监测到内存泄露后,首先做的就是dump出脚下的heap,默认的AndroidHeapDumper调用的是

    Debug.dumpHprofData(filePath);

导出当前内存的hprof分析文件,一般我们在DeviceMonitor中也得以dump出hprof文件,然后将其从dalvik格式转成标准jvm格式,然后采纳MAT举行剖析。

那么LeakCanary是怎么分析内存泄露的呢?

HaHa

LeakCanary
分析内存泄露用到了一个和Mat类似的工具叫做HaHa,使用HaHa的法门如下:

 public AnalysisResult checkForLeak(File heapDumpFile, String referenceKey) {
        long analysisStartNanoTime = System.nanoTime();

        if (!heapDumpFile.exists()) {
            Exception exception = new IllegalArgumentException("File does not exist: " + heapDumpFile);
            return failure(exception, since(analysisStartNanoTime));
        }

        try {
            HprofBuffer buffer = new MemoryMappedFileBuffer(heapDumpFile);
            HprofParser parser = new HprofParser(buffer);
            Snapshot snapshot = parser.parse();

            Instance leakingRef = findLeakingReference(referenceKey, snapshot);

            // False alarm, weak reference was cleared in between key check and heap dump.
            if (leakingRef == null) {
                return noLeak(since(analysisStartNanoTime));
            }

            return findLeakTrace(analysisStartNanoTime, snapshot, leakingRef);
        } catch (Throwable e) {
            return failure(e, since(analysisStartNanoTime));
        }
    }

归来的ActivityResult对象中带有了目的到GC
root的最短路径。LeakCanary在dump出hprof文件后,会启动一个IntentService举行解析:HeapAnalyzer瑟维斯(Service)(Service)在分析出结果未来会启动DisplayLeakService用来倡导Notification
以及将结果记录下来写在文书之中。未来每便启动LeakAnalyzerActivity就从文件里读取历史结果。

参照文档

LeakCanary
国语使用验证

LeakCanary
内存泄露监测原理研讨
:
结合源码分析leakcanary检查内存泄露的长河。

相关文章

网站地图xml地图