LeakCanary 基本使用及源码解析

作者: 落魄的安卓开发 | 来源:发表于2017-11-24 12:07 被阅读93次

之前被问过几次LeakCanary的工作原理,今天追踪代码了解一番,并进行记录方便以后查看。如有错误,还请指出来。谢谢

基本使用

  1. 在build.gradle中:

     dependencies {
       debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
       releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
     }
    
  2. 在Application中:

     private RefWatcher refWatcher;
    
     @Override
     public void onCreate() {
         super.onCreate();
         //LeakCanary 检测内存泄漏
         refWatcher = LeakCanary.install(this);
     }
    

    到这里,它就可以监控我们的Activity是否出现了内存泄漏问题了。

     public static RefWatcher getRefWatcher(Context context) {
         App application = (App) context.getApplicationContext();
         return application.refWatcher;
     }
    

    如果我们想监控某个对象是否能够造成内存泄漏就如下监控Fragment:

     @Override
     public void onDestroy() {
         super.onDestroy();
         RefWatcher refWatcher = App.initAppInstance().getRefWatcher();
         refWatcher.watch(this,getClass().getSimpleName());
     }
    

    监控Bitmap

     RefWatcher refWatcher = App.initAppInstance().getRefWatcher();
     refWatcher.watch(bitmap);
    

中文文档走你

检测Activity泄漏、watch()源码流程分析

  • 大体流程如下:

    1. 监控最终都是调用了watch(object)
    2. 给object随机一个key存储到 set集合中
    3. 以objcet为参数初始化一个弱引用
    4. 开启线程进行监控、GC、写dumpheap操作
    5. 从软引用中poll出它内部的objcet,根据是否为空来清除set中的key
    6. 最后根据set中是否包含key,判断来进行是否调用GC
    7. 调用完GC之后在进行第5部操作,根据set中是否包含key来进行保存dumpheap操作
  • 源码解析工作流程:

  • RefWatcher初始化工作

    从LeakCanary.install(this)开始:

      RefWatcher refWatcher = LeakCanary.install(this);
    
      public static RefWatcher install(Application application) {
          return install(application, DisplayLeakService.class);
      }
    

    调用了:

      public static RefWatcher install(Application application, Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
    
          //判断泄露分析进程和被分析的进程是否是同一个进程
    
          if(isInAnalyzerProcess(application)) {
              return RefWatcher.DISABLED;
          } else {
    
              //不是,则进行RefWatcher的初始化工作
    
              enableDisplayLeakActivity(application);
              ServiceHeapDumpListener heapDumpListener = new ServiceHeapDumpListener(application, listenerServiceClass);
    
              //初始化refWatcher
              RefWatcher refWatcher = androidWatcher(application, heapDumpListener);
    
              //监控Activity
              ActivityRefWatcher.installOnIcsPlus(application, refWatcher);
              
              return refWatcher;
          }
      }
    

    初始化refWatcher:

      public static RefWatcher androidWatcher(Application app, Listener heapDumpListener) {
          AndroidDebuggerControl debuggerControl = new AndroidDebuggerControl();
          AndroidHeapDumper heapDumper = new AndroidHeapDumper(app);
          heapDumper.cleanup();
          
          //到RefWatcher的构造方法
          return new RefWatcher(new AndroidWatchExecutor(), debuggerControl, GcTrigger.DEFAULT, heapDumper, heapDumpListener);
      }
    

    RefWatcher的构造方法

      public RefWatcher(Executor watchExecutor, DebuggerControl debuggerControl, GcTrigger gcTrigger,
        HeapDumper heapDumper, HeapDump.Listener heapdumpListener) {
          this.watchExecutor = checkNotNull(watchExecutor, "watchExecutor");
          this.debuggerControl = checkNotNull(debuggerControl, "debuggerControl");
          
          //手动调用GC的interface
          this.gcTrigger = checkNotNull(gcTrigger, "gcTrigger");
          
          this.heapDumper = checkNotNull(heapDumper, "heapDumper");
          this.heapdumpListener = checkNotNull(heapdumpListener, "heapdumpListener");
          
          //存储监控引用的名称的set集合
          retainedKeys = new CopyOnWriteArraySet<>();
    
          //存储监控对象的Queue
          queue = new ReferenceQueue<>();
        }
    

    至此 RefWatcher的初始化工作完成

  • 监控Activity

    由上述install中开始

      //监控Activity
      ActivityRefWatcher.installOnIcsPlus(application, refWatcher);
    

    调用过程:ActivityRefWatcher类

      public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {
          if(VERSION.SDK_INT >= 14) {
              ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
              activityRefWatcher.watchActivities();
          }
      }
    
      public void watchActivities() {
    
          //停止监控
          this.stopWatchingActivities();
    
          //给我们的application注册ActivityLifecycleCallback,生命周期监控
          this.application.registerActivityLifecycleCallbacks(this.lifecycleCallbacks);
      }
    

    生命周期监控回调: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) {
              
              //监控Activity的onDestory方法
              ActivityRefWatcher.this.onActivityDestroyed(activity);
    
          }
      };
    

    最终调用了refWatcher.watch()方法,来监控

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

    到这里我们就知道了,LeakCanary初始化之后就对Activity的onDestory方法进行了监控,如果一直没有走onDestory(),说明出现了泄漏问题。然后具体的如何监控,提示的话是在watch()方法中实现的。

  • watch()

      public void watch(Object watchedReference) {
        watch(watchedReference, "");
      }
    
      public void watch(Object watchedReference, String referenceName) {
          checkNotNull(watchedReference, "watchedReference");
          checkNotNull(referenceName, "referenceName");
          if (debuggerControl.isDebuggerAttached()) {
            return;
          }
          final long watchStartNanoTime = System.nanoTime();
          String key = UUID.randomUUID().toString();
    
          //给引用object随机一个key存到retainedKeys中
          retainedKeys.add(key);
    
          //初始化一个自定义的弱引用,将监控的引用object 存到弱引用中 ,同时记录下内部 key 和 name
          final KeyedWeakReference reference =
              new KeyedWeakReference(watchedReference, key, referenceName, queue);
      
          //异步执行 检查泄漏操作及GC操作
          watchExecutor.execute(new Runnable() {
            @Override public void run() {
              ensureGone(reference, watchStartNanoTime);
          }
        });
      }
    
    
      //检查是否泄漏、GC、保存heapdump信息的方法
      void ensureGone(KeyedWeakReference reference, long watchStartNanoTime) {
          long gcStartNanoTime = System.nanoTime();
      
          long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
    
          //清除retainedKeys中的key
          removeWeaklyReachableReferences();
          //判断 reference的key是否还在set集合中,如果不在 就结束了。如果还在就执行gc操作
          if (gone(reference) || debuggerControl.isDebuggerAttached()) {
            return;
          }
          gcTrigger.runGc();
          //执行完 GC 之后,再进行清除retainedKeys中的key操作
          removeWeaklyReachableReferences();
          //判断 reference的key是否还在set集合中,如果还在就执行将heapDump记录下来
          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));
          }
        }
    
      //将弱引用中的内容取出来,如果不是空就将存储到set集合中的key删除掉
      private void removeWeaklyReachableReferences() {
          // WeakReferences are enqueued as soon as the object to which they point to becomes weakly
          // reachable. This is before finalization or garbage collection has actually happened.
          KeyedWeakReference ref;
          while ((ref = (KeyedWeakReference) queue.poll()) != null) {
            retainedKeys.remove(ref.key);
          }
        }
    
      //判断 弱引用的key是否还在 set集合中
      private boolean gone(KeyedWeakReference reference) {
         return !retainedKeys.contains(reference.key);
      }
    

到这里整体流程就OK了,具体的那个将dumpheap保存下来没有写。

相关文章

网友评论

    本文标题:LeakCanary 基本使用及源码解析

    本文链接:https://www.haomeiwen.com/subject/aewxbxtx.html