日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
帶你學開源項目:LeakCanary-如何檢測Activity是否泄漏

OOM 是 Android 開發(fā)中常見的問題,而內存泄漏往往是罪魁禍首。

創(chuàng)新互聯(lián)制作網(wǎng)站網(wǎng)頁找三站合一網(wǎng)站制作公司,專注于網(wǎng)頁設計,網(wǎng)站制作、成都網(wǎng)站設計,網(wǎng)站設計,企業(yè)網(wǎng)站搭建,網(wǎng)站開發(fā),建網(wǎng)站業(yè)務,680元做網(wǎng)站,已為上千多家服務,創(chuàng)新互聯(lián)網(wǎng)站建設將一如既往的為我們的客戶提供最優(yōu)質的網(wǎng)站建設、網(wǎng)絡營銷推廣服務!

為了簡單方便的檢測內存泄漏,Square 開源了 LeakCanary ,它可以實時監(jiān)測 Activity 是否發(fā)生了泄漏,一旦發(fā)現(xiàn)就會自動彈出提示及相關的泄漏信息供分析。

本文的目的是試圖通過分析 LeakCanary 源碼來探討它的 Activity 泄漏檢測機制。

LeakCanary 使用方式

為了將 LeakCanary 引入到我們的項目里,我們只需要做以下兩步:

 
 
 
 
  1. dependencies {
  2.  debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
  3.  releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
  4.  testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'}public class ExampleApplication extends Application {  @Override public void onCreate() {    super.onCreate();    if (LeakCanary.isInAnalyzerProcess(this)) {      // This process is dedicated to LeakCanary for heap analysis.
  5.       // You should not init your app in this process.
  6.       return;
  7.     }
  8.     LeakCanary.install(this);
  9.   }
  10. }

 可以看出,最關鍵的就是 LeakCanary.install(this); 這么一句話,正式開啟了 LeakCanary 的大門,未來它就會自動幫我們檢測內存泄漏,并在發(fā)生泄漏是彈出通知信息。

從 LeakCanary.install(this); 開始

下面我們來看下它做了些什么?

 
 
 
 
  1. public static RefWatcher install(Application application) {  return install(application, DisplayLeakService.class,
  2.       AndroidExcludedRefs.createAppDefaults().build());
  3. }public static RefWatcher install(Application application,
  4.     Class listenerServiceClass,
  5.     ExcludedRefs excludedRefs) {  if (isInAnalyzerProcess(application)) {    return RefWatcher.DISABLED;
  6.   }
  7.   enableDisplayLeakActivity(application);
  8.   HeapDump.Listener heapDumpListener =      new ServiceHeapDumpListener(application, listenerServiceClass);
  9.   RefWatcher refWatcher = androidWatcher(application, heapDumpListener, excludedRefs);
  10.   ActivityRefWatcher.installOnIcsPlus(application, refWatcher);  return refWatcher;

首先,我們先看最重要的部分,就是:

 
 
 
 
  1. RefWatcher refWatcher = androidWatcher(application, heapDumpListener, excludedRefs);
  2. ActivityRefWatcher.installOnIcsPlus(application, refWatcher); 

先生成了一個 RefWatcher ,這個東西非常關鍵,從名字可以看出,它是用來 watch Reference 的,也就是用來一個監(jiān)控引用的工具。然后再把 refWatcher 和我們自己提供的 application 傳入到 ActivityRefWatcher.installOnIcsPlus(application, refWatcher); 這句里面,繼續(xù)看。

 
 
 
 
  1. public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {
  2.     ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
  3.     activityRefWatcher.watchActivities();

創(chuàng)建了一個 ActivityRefWatcher ,大家應該能感受到,這個東西就是用來監(jiān)控我們的 Activity 泄漏狀況的,它調用 watchActivities() 方法,就可以開始進行監(jiān)控了。下面就是它監(jiān)控的核心原理:

 
 
 
 
  1. public void watchActivities() {
  2.   application.registerActivityLifecycleCallbacks(lifecycleCallbacks);

它向 application 里注冊了一個 ActivitylifecycleCallbacks 的回調函數(shù),可以用來監(jiān)聽 Application 整個生命周期所有 Activity 的 lifecycle 事件。再看下這個 lifecycleCallbacks 是什么?

 
 
 
 
  1. private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =    new Application.ActivityLifecycleCallbacks() {      @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
  2.       }      @Override public void onActivityStarted(Activity activity) {
  3.       }      @Override public void onActivityResumed(Activity activity) {
  4.       }      @Override public void onActivityPaused(Activity activity) {
  5.       }      @Override public void onActivityStopped(Activity activity) {
  6.       }      @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
  7.       }      @Override public void onActivityDestroyed(Activity activity) {
  8.         ActivityRefWatcher.this.onActivityDestroyed(activity);
  9.       }
  10.     };

 原來它只監(jiān)聽了所有 Activity 的 onActivityDestroyed 事件,當 Activity 被 Destory 時,調用 ActivityRefWatcher.this.onActivityDestroyed(activity); 函數(shù)。

猜測下,正常情況下,當一個這個函數(shù)應該 activity 被 Destory 時,那這個 activity 對象應該變成 null 才是正確的。如果沒有變成null,那么就意味著發(fā)生了內存泄漏。

因此我們向,這個函數(shù) ActivityRefWatcher.this.onActivityDestroyed(activity); 應該是用來監(jiān)聽 activity 對象是否變成了 null。繼續(xù)看。

 
 
 
 
  1. void onActivityDestroyed(Activity activity) {
  2.   refWatcher.watch(activity);
  3. }
  4. RefWatcher refWatcher = androidWatcher(application, heapDumpListener, excludedRefs); 

可以看出,這個函數(shù)把目標 activity 對象傳給了 RefWatcher ,讓它去監(jiān)控這個 activity 是否被正?;厥樟?,若未被回收,則意味著發(fā)生了內存泄漏。

RefWatcher 如何監(jiān)控 activity 是否被正?;厥漳?

我們先來看看這個 RefWatcher 究竟是個什么東西?

 
 
 
 
  1. public static RefWatcher androidWatcher(Context context, HeapDump.Listener heapDumpListener,
  2.     ExcludedRefs excludedRefs) {
  3.   AndroidHeapDumper heapDumper = new AndroidHeapDumper(context, leakDirectoryProvider);
  4.   heapDumper.cleanup();  int watchDelayMillis = 5000;
  5.   AndroidWatchExecutor executor = new AndroidWatchExecutor(watchDelayMillis);  return new RefWatcher(executor, debuggerControl, GcTrigger.DEFAULT, heapDumper,
  6.       heapDumpListener, excludedRefs);

這里面涉及到兩個新的對象: AndroidHeapDumper 和 AndroidWatchExecutor ,前者用來 dump 堆內存狀態(tài)的,后者則是用來 watch 一個引用的監(jiān)聽器。具體原理后面再看??傊?,這里已經(jīng)生成好了一個 RefWatcher 對象了。

現(xiàn)在再看上面 onActivityDestroyed(Activity activity) 里調用的 refWatcher.watch(activity); ,下面來看下這個最為核心的 watch(activity) 方法,了解它是如何監(jiān)控 activity 是否被回收的。

 
 
 
 
  1. private final Set retainedKeys;public void watch(Object activity, String referenceName) {
  2.   String key = UUID.randomUUID().toString();
  3.   retainedKeys.add(key);  final KeyedWeakReference reference =      new KeyedWeakReference(activity, key, referenceName, queue);
  4.   watchExecutor.execute(new Runnable() {    @Override public void run() {
  5.       ensureGone(reference, watchStartNanoTime);
  6.     }
  7.   });
  8. }final class KeyedWeakReference extends WeakReference {  public final String key;  public final String name;
  9. 可以看到,它首先把我們傳入的 activity 包裝成了一個 KeyedWeakReference (可以暫時看成一個普通的 WeakReference),然后 watchExecutor 會去執(zhí)行一個 Runnable,這個 Runnable 會調用 ensureGone(reference, watchStartNanoTime) 函數(shù)。

    看這個函數(shù)之前猜測下,我們知道 watch 函數(shù)本身就是用來監(jiān)聽 activity 是否被正?;厥眨@就涉及到兩個問題:

    1. 何時去檢查它是否回收?
    2. 如何有效地檢查它真的被回收?

    所以我們覺得 ensureGone 函數(shù)本身要做的事正如它的名字,就是確保 reference 被回收掉了,否則就意味著內存泄漏。

    核心函數(shù):ensureGone(reference) 檢測回收

    下面來看這個函數(shù)實現(xiàn):

     
     
     
     
    1. void ensureGone(KeyedWeakReference reference, long watchStartNanoTime) {
    2.   removeWeaklyReachableReferences();  if (gone(reference) || debuggerControl.isDebuggerAttached()) {    return;
    3.   }
    4.   gcTrigger.runGc();
    5.   removeWeaklyReachableReferences();  if (!gone(reference)) {
    6.     File heapDumpFile = heapDumper.dumpHeap();
    7.     heapdumpListener.analyze(        new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
    8.             gcDurationMs, heapDumpDurationMs));
    9.   }
    10. }private boolean gone(KeyedWeakReference reference) {  return !retainedKeys.contains(reference.key);
    11. }private void removeWeaklyReachableReferences() {
    12.   KeyedWeakReference ref;  while ((ref = (KeyedWeakReference) queue.poll()) != null) {
    13.     retainedKeys.remove(ref.key);
    14.   }

    這里先來解釋下 WeakReference 和 ReferenceQueue 的工作原理。

         1.弱引用 WeakReference

     被強引用的對象就算發(fā)生 OOM 也永遠不會被垃圾回收機回收;被弱引用的對象,只要被垃圾回收器發(fā)現(xiàn)就會立即被回收;被軟引用的對象,具備內存敏感性,只有內存不足時才會被回收,常用來做內存敏感緩存器;虛引用則任意時刻都可能被回收,使用較少。

         2.引用隊列 ReferenceQueue

    我們常用一個 WeakReference reference = new WeakReference(activity); ,這里我們創(chuàng)建了一個 reference 來弱引用到某個 activity ,當這個 activity 被垃圾回收器回收后,這個 reference 會被放入內部的 ReferenceQueue 中。也就是說,從隊列 ReferenceQueue 取出來的所有 reference ,它們指向的真實對象都已經(jīng)成功被回收了。

    然后再回到上面的代碼。

    在一個 activity 傳給 RefWatcher 時會創(chuàng)建一個***的 key 對應這個 activity,該key存入一個集合 retainedKeys 中。也就是說,所有我們想要觀測的 activity 對應的*** key 都會被放入 retainedKeys 集合中。

    基于我們對 ReferenceQueue 的了解,只要把隊列中所有的 reference 取出來,并把對應 retainedKeys 里的key移除,剩下的 key 對應的對象都沒有被回收。

    1. ensureGone 首先調用 removeWeaklyReachableReferences 把已被回收的對象的 key 從 retainedKeys 移除,剩下的 key 都是未被回收的對象;
    2. if

      網(wǎng)站名稱:帶你學開源項目:LeakCanary-如何檢測Activity是否泄漏
      URL分享:http://www.dlmjj.cn/article/dpjijcg.html