LeakCanary 1.3版本源碼分析

爲什麼是1.3版本呢,是因爲之前看過的源碼,有幾點沒說明白的,補充一下。如有錯誤,還請指出來。謝謝

基本使用

  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()源碼流程分析

  • 核心內容

    WeakReference弱引用,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否(這一點與SoftReference不同),都會回收它的內存。由於垃圾回收器是一個優先級很低的線程,因此不一定會很快發現那些只具有弱引用的對象。

    WeakReference和ReferenceQueue聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。

       @Test
       public void addition_isCorrect() throws Exception {
           ReferenceQueue<MyClass> queue = new ReferenceQueue<>();
           MyClass m = new MyClass();
           // 聲明weakreference
           WeakReference w = new WeakReference(m,queue);
           // 斷開強引用
           m = null;
           System.gc();
           // 睡眠3秒是因爲,主動調用gc是不一定會立馬執行
           Thread.sleep(3000);
           // 回收後會被加入到queue中,所以queue.poll()出來不爲null,就說明被回收了
           while(queue.poll()!=null){
                 System.out.println("被回收了");
           }
      }
    
  • 大體流程如下:

    1. 監控最終都是調用了watch(object)
    2. 給object隨機一個key存儲到 set集合中
    3. 以objcet爲參數初始化一個KeyedWeakReference引用object
    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));
          }
        }
    
      //講object從queue隊列中取出來,如果不是空說明已經被GC回收了,就將存儲到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保存下來沒有寫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章