「Leakcanary 源码分析」看这一篇就够了


原创作者:Mr.S ,授权发布,感谢;

他目前人在北京,3年工作经验,正在寻找新的机会,如果你刚好有资源,可以联系我,微信/留言都可以,感谢。


「Leakcanary 」是我们经常用于检测内存泄漏的工具,简单的使用方式,内存泄漏的可视化,是我们开发中必备的工具之一。

分析源码之前

Leakcanary 大神的 github ,最好的老师。

一、使用

1、配置
1dependencies {2  debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3'3  releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'4  // Optional, if you use support library fragments:5  debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3'6}
2  debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3'
3  releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'
4  // Optional, if you use support library fragments:
5  debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3'
6}
2、简单使用
 1public class ExampleApplication extends Application { 2 3  @Override public void onCreate() { 4    super.onCreate(); 5    if (LeakCanary.isInAnalyzerProcess(this)) { 6      // This process is dedicated to LeakCanary for heap analysis. 7      // You should not init your app in this process. 8      return; 9    }10    LeakCanary.install(this);11    // Normal app init code...12  }13}public class ExampleApplication extends Application {
2
3  @Override public void onCreate() {
4    super.onCreate();
5    if (LeakCanary.isInAnalyzerProcess(this)) {
6      // This process is dedicated to LeakCanary for heap analysis.
7      // You should not init your app in this process.
8      return;
9    }
10    LeakCanary.install(this);
11    // Normal app init code...
12  }
13}

超级简单的配置和使用方式。最后就会得出以下的事例说明。

640?wx_fmt=png

二、准备工作

1、Reference

Reference 把内存分为 4 种状态,Active 、 Pending 、 Enqueued 、 Inactive。

2、ReferenceQueue

引用队列,在 Reference 被回收的时候,Reference 会被添加到 ReferenceQueue 中

3、如果检测一个对象是否被回收

需要采用 Reference + ReferenceQueue

 1//创建一个引用队列   2ReferenceQueue queue = new ReferenceQueue();   3 4// 创建弱引用,此时状态为Active,并且Reference.pending为空, 5// 当前Reference.queue = 上面创建的queue,并且next=null   6// reference 创建并关联 queue 7WeakReference reference = new WeakReference(new Object(), queue);   8 9// 当GC执行后,由于是弱引用,所以回收该object对象,并且置于pending上,此时reference的状态为PENDING  10System.gc();  1112// ReferenceHandler从 pending 中取下该元素,并且将该元素放入到queue中,13//此时Reference状态为ENQUEUED,Reference.queue = ReferenceENQUEUED 1415// 当从queue里面取出该元素,则变为INACTIVE,Reference.queue = Reference.NULL  16Reference reference1 = queue.remove();  //创建一个引用队列  
2ReferenceQueue queue = new ReferenceQueue();  
3
4// 创建弱引用,此时状态为Active,并且Reference.pending为空,
5// 当前Reference.queue = 上面创建的queue,并且next=null  
6// reference 创建并关联 queue
7WeakReference reference = new WeakReference(new Object(), queue);  
8
9// 当GC执行后,由于是弱引用,所以回收该object对象,并且置于pending上,此时reference的状态为PENDING  
10System.gc();  
11
12// ReferenceHandler从 pending 中取下该元素,并且将该元素放入到queue中,
13//此时Reference状态为ENQUEUED,Reference.queue = ReferenceENQUEUED 
14
15// 当从queue里面取出该元素,则变为INACTIVE,Reference.queue = Reference.NULL  
16Reference reference1 = queue.remove();  

在 Reference 类加载的时候,Java 虚拟机会会创建一个最大优先级的后台线程,这个线程的工作就是不断检测 pending 是否为 null,如果不为 null,那么就将它放到 ReferenceQueue。因为 pending 不为 null,就说明引用所指向的对象已经被 GC,变成了不可达。

4、ActivityLifecycleCallbacks

用于监听所有 Activity 生命周期的回调方法。

 1  private final Application.ActivityLifecycleCallbacks lifecycleCallbacks = 2      new Application.ActivityLifecycleCallbacks() { 3        @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { 4        } 5 6        @Override public void onActivityStarted(Activity activity) { 7        } 8 9        @Override public void onActivityResumed(Activity activity) {10        }1112        @Override public void onActivityPaused(Activity activity) {13        }1415        @Override public void onActivityStopped(Activity activity) {16        }1718        @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {19        }2021        @Override public void onActivityDestroyed(Activity activity) {22          ActivityRefWatcher.this.onActivityDestroyed(activity);23        }24      };private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
2      new Application.ActivityLifecycleCallbacks() {
3        @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
4        }
5
6        @Override public void onActivityStarted(Activity activity) {
7        }
8
9        @Override public void onActivityResumed(Activity activity) {
10        }
11
12        @Override public void onActivityPaused(Activity activity) {
13        }
14
15        @Override public void onActivityStopped(Activity activity) {
16        }
17
18        @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
19        }
20
21        @Override public void onActivityDestroyed(Activity activity) {
22          ActivityRefWatcher.this.onActivityDestroyed(activity);
23        }
24      };
5、Heap Dump

Heap Dump也叫堆转储文件,是一个Java进程在某个时间点上的内存快照。

三、原理说明

1、监听 Activity 的生命周期。
2、在 onDestory 的时候,创建对应的 Actitity 的 Refrence 和 相应的 RefrenceQueue,启动后台进程去检测。
3、一段时间后,从 RefrenceQueue 中读取,如果有这个 Actitity 的 Refrence,那么说明这个 Activity 的 Refrence 已经被回收,但是如果 RefrenceQueue 没有这个 Actitity 的 Refrence 那就说明出现了内存泄漏。
4、dump 出 hprof 文件,找到泄漏路径。

分析源码

程序的唯一入口 LeakCanary.install(this);

1、install

DisplayLeakService  这个类负责发起 Notification 以及将结果记录下来写在文件里面。以后每次启动LeakAnalyzerActivity就从这个文件里读取历史结果,并展示给我们。

1  public static RefWatcher install(Application application) {2    return install(application, DisplayLeakService.class);3  }public static RefWatcher install(Application application) {
2    return install(application, DisplayLeakService.class);
3  }
 1  public static RefWatcher install(Application application, 2      Class<? extends AbstractAnalysisResultService> listenerServiceClass) { 3   //如果在主线程 那么返回一个无用的 RefWatcher  详解 1.1 4    if (isInAnalyzerProcess(application)) { 5      return RefWatcher.DISABLED; 6    } 7    //把 DisplayLeakActivity 设置为可用  用于显示 DisplayLeakActivity 就是我们看到的那个分析界面 8    enableDisplayLeakActivity(application); 9   // 详解 1.210    HeapDump.Listener heapDumpListener =11        new ServiceHeapDumpListener(application, listenerServiceClass);12    //详解 213    RefWatcher refWatcher = androidWatcher(application, heapDumpListener);14    详解 315    ActivityRefWatcher.installOnIcsPlus(application, refWatcher);16    return refWatcher;17  }public static RefWatcher install(Application application,
2      Class<? extends AbstractAnalysisResultService> listenerServiceClass)
 
{
3   //如果在主线程 那么返回一个无用的 RefWatcher  详解 1.1
4    if (isInAnalyzerProcess(application)) {
5      return RefWatcher.DISABLED;
6    }
7    //把 DisplayLeakActivity 设置为可用  用于显示 DisplayLeakActivity 就是我们看到的那个分析界面
8    enableDisplayLeakActivity(application);
9   // 详解 1.2
10    HeapDump.Listener heapDumpListener =
11        new ServiceHeapDumpListener(application, listenerServiceClass);
12    //详解 2
13    RefWatcher refWatcher = androidWatcher(application, heapDumpListener);
14    详解 3
15    ActivityRefWatcher.installOnIcsPlus(application, refWatcher);
16    return refWatcher;
17  }
1.1 isInAnalyzerProcess

因为 分析的进程是硬外一个独立进程 所以要判断是否是主进程,这个工作需要在 AnalyzerProcess 中进行。

1  public static boolean isInAnalyzerProcess(Context context) {2    return isInServiceProcess(context, HeapAnalyzerService.class);3  }public static boolean isInAnalyzerProcess(Context context) {
2    return isInServiceProcess(context, HeapAnalyzerService.class);
3  }

把App 的进程 和 这个 Service 进程进行对比 。

 1  private static boolean isInServiceProcess(Context context, 2      Class<? extends Service> serviceClass) { 3    PackageManager packageManager = context.getPackageManager(); 4    PackageInfo packageInfo; 5    try { 6      packageInfo = packageManager.getPackageInfo(context.getPackageName(), GET_SERVICES); 7    } catch (Exception e) { 8      Log.e("AndroidUtils", "Could not get package info for " + context.getPackageName(), e); 9      return false;10    }11    String mainProcess = packageInfo.applicationInfo.processName;1213    ComponentName component = new ComponentName(context, serviceClass);14    ServiceInfo serviceInfo;15    try {16      serviceInfo = packageManager.getServiceInfo(component, 0);17    } catch (PackageManager.NameNotFoundException ignored) {18      // Service is disabled.19      return false;20    }2122    if (serviceInfo.processName.equals(mainProcess)) {23      Log.e("AndroidUtils",24          "Did not expect service " + serviceClass + " to run in main process " + mainProcess);25      // Technically we are in the service process, but we're not in the service dedicated process.26      return false;27    }2829    int myPid = android.os.Process.myPid();30    ActivityManager activityManager =31        (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);32    ActivityManager.RunningAppProcessInfo myProcess = null;3334    for (ActivityManager.RunningAppProcessInfo process : activityManager.getRunningAppProcesses()) {35      if (process.pid == myPid) {36        myProcess = process;37        break;38      }39    }40    if (myProcess == null) {41      Log.e("AndroidUtils", "Could not find running process for " + myPid);42      return false;43    }44 //把App 的进程 和 这个 Service 进程进行对比 45    return myProcess.processName.equals(serviceInfo.processName);46  }private static boolean isInServiceProcess(Context context,
2      Class<? extends ServiceserviceClass{
3    PackageManager packageManager = context.getPackageManager();
4    PackageInfo packageInfo;
5    try {
6      packageInfo = packageManager.getPackageInfo(context.getPackageName(), GET_SERVICES);
7    } catch (Exception e) {
8      Log.e("AndroidUtils""Could not get package info for " + context.getPackageName(), e);
9      return false;
10    }
11    String mainProcess = packageInfo.applicationInfo.processName;
12
13    ComponentName component = new ComponentName(context, serviceClass);
14    ServiceInfo serviceInfo;
15    try {
16      serviceInfo = packageManager.getServiceInfo(component, 0);
17    } catch (PackageManager.NameNotFoundException ignored) {
18      // Service is disabled.
19      return false;
20    }
21
22    if (serviceInfo.processName.equals(mainProcess)) {
23      Log.e("AndroidUtils",
24          "Did not expect service " + serviceClass + " to run in main process " + mainProcess);
25      // Technically we are in the service process, but we're not in the service dedicated process.
26      return false;
27    }
28
29    int myPid = android.os.Process.myPid();
30    ActivityManager activityManager =
31        (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
32    ActivityManager.RunningAppProcessInfo myProcess = null;
33
34    for (ActivityManager.RunningAppProcessInfo process : activityManager.getRunningAppProcesses()) {
35      if (process.pid == myPid) {
36        myProcess = process;
37        break;
38      }
39    }
40    if (myProcess == null) {
41      Log.e("AndroidUtils""Could not find running process for " + myPid);
42      return false;
43    }
44 //把App 的进程 和 这个 Service 进程进行对比 
45    return myProcess.processName.equals(serviceInfo.processName);
46  }
1.2 ServiceHeapDumpListener

设置 DisplayLeakService 和 HeapAnalyzerService 的可用。
analyze 方法,开始分析 HeapDump。

 1public final class ServiceHeapDumpListener implements HeapDump.Listener { 2 3  private final Context context; 4  private final Class<? extends AbstractAnalysisResultService> listenerServiceClass; 5 6  public ServiceHeapDumpListener(Context context, 7      Class<? extends AbstractAnalysisResultService> listenerServiceClass) { 8    LeakCanary.setEnabled(context, listenerServiceClass, true); 9    LeakCanary.setEnabled(context, HeapAnalyzerService.class, true);10    this.listenerServiceClass = checkNotNull(listenerServiceClass, "listenerServiceClass");11    this.context = checkNotNull(context, "context").getApplicationContext();12  }1314  @Override public void analyze(HeapDump heapDump) {15    checkNotNull(heapDump, "heapDump");16    HeapAnalyzerService.runAnalysis(context, heapDump, listenerServiceClass);17  }18}public final class ServiceHeapDumpListener implements HeapDump.Listener {
2
3  private final Context context;
4  private final Class<? extends AbstractAnalysisResultService> listenerServiceClass;
5
6  public ServiceHeapDumpListener(Context context,
7      Class<? extends AbstractAnalysisResultService> listenerServiceClass)
 
{
8    LeakCanary.setEnabled(context, listenerServiceClass, true);
9    LeakCanary.setEnabled(context, HeapAnalyzerService.class, true);
10    this.listenerServiceClass = checkNotNull(listenerServiceClass, "listenerServiceClass");
11    this.context = checkNotNull(context, "context").getApplicationContext();
12  }
13
14  @Override public void analyze(HeapDump heapDump) {
15    checkNotNull(heapDump, "heapDump");
16    HeapAnalyzerService.runAnalysis(context, heapDump, listenerServiceClass);
17  }
18}

2、RefWatcher

1  private final Executor watchExecutor;2  private final DebuggerControl debuggerControl;3  private final GcTrigger gcTrigger;4  private final HeapDumper heapDumper;5  private final Set<String> retainedKeys;6  private final ReferenceQueue<Object> queue;7  private final HeapDump.Listener heapdumpListener;private final Executor watchExecutor;
2  private final DebuggerControl debuggerControl;
3  private final GcTrigger gcTrigger;
4  private final HeapDumper heapDumper;
5  private final Set<String> retainedKeys;
6  private final ReferenceQueue<Object> queue;
7  private final HeapDump.Listener heapdumpListener;

这里创建我们所需要的 RefWatcher。

1  public static RefWatcher androidWatcher(Application app, HeapDump.Listener heapDumpListener) {2    DebuggerControl debuggerControl = new AndroidDebuggerControl();3    AndroidHeapDumper heapDumper = new AndroidHeapDumper(app);4    heapDumper.cleanup();5    return new RefWatcher(new AndroidWatchExecutor(), debuggerControl, GcTrigger.DEFAULT,6        heapDumper, heapDumpListener);7  }public static RefWatcher androidWatcher(Application app, HeapDump.Listener heapDumpListener) {
2    DebuggerControl debuggerControl = new AndroidDebuggerControl();
3    AndroidHeapDumper heapDumper = new AndroidHeapDumper(app);
4    heapDumper.cleanup();
5    return new RefWatcher(new AndroidWatchExecutor(), debuggerControl, GcTrigger.DEFAULT,
6        heapDumper, heapDumpListener);
7  }

3、ActivityRefWatcher

1  public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {2    if (SDK_INT < ICE_CREAM_SANDWICH) {3      // If you need to support Android < ICS, override onDestroy() in your base activity.4      return;5    }6    ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);7    activityRefWatcher.watchActivities();8  }public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {
2    if (SDK_INT < ICE_CREAM_SANDWICH) {
3      // If you need to support Android < ICS, override onDestroy() in your base activity.
4      return;
5    }
6    ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
7    activityRefWatcher.watchActivities();
8  }
 1  //注册 lifecycleCallbacks 2  public void watchActivities() { 3    // Make sure you don't get installed twice. 4    stopWatchingActivities(); 5    application.registerActivityLifecycleCallbacks(lifecycleCallbacks); 6  } 7  //ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks 8  //就是 mActivityLifecycleCallbacks 的添加 9  public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {10        synchronized (mActivityLifecycleCallbacks) {11            mActivityLifecycleCallbacks.add(callback);12        }13    }14  // 注销 lifecycleCallbacks15   public void stopWatchingActivities() {16    application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks);17  }18  //  //就是 mActivityLifecycleCallbacks 的 移除19  public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {20        synchronized (mActivityLifecycleCallbacks) {21            mActivityLifecycleCallbacks.remove(callback);22        }23    }//注册 lifecycleCallbacks
2  public void watchActivities() {
3    // Make sure you don't get installed twice.
4    stopWatchingActivities();
5    application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
6  }
7  //ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks
8  //就是 mActivityLifecycleCallbacks 的添加
9  public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
10        synchronized (mActivityLifecycleCallbacks) {
11            mActivityLifecycleCallbacks.add(callback);
12        }
13    }
14  // 注销 lifecycleCallbacks
15   public void stopWatchingActivities() {
16    application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks);
17  }
18  //  //就是 mActivityLifecycleCallbacks 的 移除
19  public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
20        synchronized (mActivityLifecycleCallbacks) {
21            mActivityLifecycleCallbacks.remove(callback);
22        }
23    }

本质就是在 Activity 的 onActivityDestroyed 方法里 执行   refWatcher.watch(activity);

 1private final Application.ActivityLifecycleCallbacks lifecycleCallbacks = 2      new Application.ActivityLifecycleCallbacks() { 3        @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { 4        } 5 6        @Override public void onActivityStarted(Activity activity) { 7        } 8 9        @Override public void onActivityResumed(Activity activity) {10        }1112        @Override public void onActivityPaused(Activity activity) {13        }1415        @Override public void onActivityStopped(Activity activity) {16        }1718        @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {19        }2021        @Override public void onActivityDestroyed(Activity activity) {22          ActivityRefWatcher.this.onActivityDestroyed(activity);23        }24      };2526  void onActivityDestroyed(Activity activity) {27    refWatcher.watch(activity);28  }private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
2      new Application.ActivityLifecycleCallbacks() {
3        @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
4        }
5
6        @Override public void onActivityStarted(Activity activity) {
7        }
8
9        @Override public void onActivityResumed(Activity activity) {
10        }
11
12        @Override public void onActivityPaused(Activity activity) {
13        }
14
15        @Override public void onActivityStopped(Activity activity) {
16        }
17
18        @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
19        }
20
21        @Override public void onActivityDestroyed(Activity activity) {
22          ActivityRefWatcher.this.onActivityDestroyed(activity);
23        }
24      };
25
26  void onActivityDestroyed(Activity activity) {
27    refWatcher.watch(activity);
28  }

4、watch

 1  public void watch(Object watchedReference, String referenceName) { 2    checkNotNull(watchedReference, "watchedReference"); 3    checkNotNull(referenceName, "referenceName"); 4    if (debuggerControl.isDebuggerAttached()) { 5      return; 6    } 7    //随机生成 watchedReference 的 key 保证其唯一性 8    final long watchStartNanoTime = System.nanoTime(); 9    String key = UUID.randomUUID().toString();10    retainedKeys.add(key);11    //这个一个弱引用的子类拓展类 用于 我们之前所说的 watchedReference 和  queue 的联合使用12    final KeyedWeakReference reference =13        new KeyedWeakReference(watchedReference, key, referenceName, queue);1415    watchExecutor.execute(new Runnable() {16      @Override public void run() {17      //重要方法,确然是否 内存泄漏18        ensureGone(reference, watchStartNanoTime);19      }20    });21  }public void watch(Object watchedReference, String referenceName) {
2    checkNotNull(watchedReference, "watchedReference");
3    checkNotNull(referenceName, "referenceName");
4    if (debuggerControl.isDebuggerAttached()) {
5      return;
6    }
7    //随机生成 watchedReference 的 key 保证其唯一性
8    final long watchStartNanoTime = System.nanoTime();
9    String key = UUID.randomUUID().toString();
10    retainedKeys.add(key);
11    //这个一个弱引用的子类拓展类 用于 我们之前所说的 watchedReference 和  queue 的联合使用
12    final KeyedWeakReference reference =
13        new KeyedWeakReference(watchedReference, key, referenceName, queue);
14
15    watchExecutor.execute(new Runnable() {
16      @Override public void run() {
17      //重要方法,确然是否 内存泄漏
18        ensureGone(reference, watchStartNanoTime);
19      }
20    });
21  }
 1final class KeyedWeakReference extends WeakReference<Object> { 2  public final String key; 3  public final String name; 4 5  KeyedWeakReference(Object referent, String key, String name, 6      ReferenceQueue<Object> referenceQueue) { 7    super(checkNotNull(referent, "referent"), checkNotNull(referenceQueue, "referenceQueue")); 8    this.key = checkNotNull(key, "key"); 9    this.name = checkNotNull(name, "name");10  }11}final class KeyedWeakReference extends WeakReference<Object{
2  public final String key;
3  public final String name;
4
5  KeyedWeakReference(Object referent, String key, String name,
6      ReferenceQueue<Object> referenceQueue) {
7    super(checkNotNull(referent, "referent"), checkNotNull(referenceQueue, "referenceQueue"));
8    this.key = checkNotNull(key, "key");
9    this.name = checkNotNull(name, "name");
10  }
11}

5、ensureGone

 1  void ensureGone(KeyedWeakReference reference, long watchStartNanoTime) { 2    long gcStartNanoTime = System.nanoTime(); 3 4    long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime); 5  //把 queue 的引用 根据 key 从 retainedKeys 中引出 。 6  //retainedKeys 中剩下的就是没有分析和内存泄漏的引用的 key 7  removeWeaklyReachableReferences(); 8  //如果内存没有泄漏 或者处于 debug 模式那么就直接返回 9    if (gone(reference) || debuggerControl.isDebuggerAttached()) {10      return;11    }12    //如果内存依旧没有被释放 那么在 GC 一次13    gcTrigger.runGc();14    //再次 清理下 retainedKeys15    removeWeaklyReachableReferences();16    //最后还有 就是说明内存泄漏了 17    if (!gone(reference)) {18      long startDumpHeap = System.nanoTime();19      long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);20//dump 出 Head 报告21      File heapDumpFile = heapDumper.dumpHeap();2223      if (heapDumpFile == null) {24        // Could not dump the heap, abort.25        return;26      }27      long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);28    //最后进行分析 这份 HeapDump  29    //LeakCanary 分析内存泄露用的是一个第三方工具 HAHA 别笑 真的是这个名字30    heapdumpListener.analyze(31          new HeapDump(heapDumpFile, reference.key, reference.name, watchDurationMs, gcDurationMs,32              heapDumpDurationMs));33    }34  }void ensureGone(KeyedWeakReference reference, long watchStartNanoTime{
2    long gcStartNanoTime = System.nanoTime();
3
4    long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
5  //把 queue 的引用 根据 key 从 retainedKeys 中引出 。
6  //retainedKeys 中剩下的就是没有分析和内存泄漏的引用的 key
7  removeWeaklyReachableReferences();
8  //如果内存没有泄漏 或者处于 debug 模式那么就直接返回
9    if (gone(reference) || debuggerControl.isDebuggerAttached()) {
10      return;
11    }
12    //如果内存依旧没有被释放 那么在 GC 一次
13    gcTrigger.runGc();
14    //再次 清理下 retainedKeys
15    removeWeaklyReachableReferences();
16    //最后还有 就是说明内存泄漏了 
17    if (!gone(reference)) {
18      long startDumpHeap = System.nanoTime();
19      long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
20//dump 出 Head 报告
21      File heapDumpFile = heapDumper.dumpHeap();
22
23      if (heapDumpFile == null) {
24        // Could not dump the heap, abort.
25        return;
26      }
27      long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
28    //最后进行分析 这份 HeapDump  
29    //LeakCanary 分析内存泄露用的是一个第三方工具 HAHA 别笑 真的是这个名字
30    heapdumpListener.analyze(
31          new HeapDump(heapDumpFile, reference.key, reference.name, watchDurationMs, gcDurationMs,
32              heapDumpDurationMs));
33    }
34  }
 1  private void removeWeaklyReachableReferences() { 2    // WeakReferences are enqueued as soon as the object to which they point to becomes weakly 3    // reachable. This is before finalization or garbage collection has actually happened. 4    KeyedWeakReference ref; 5    while ((ref = (KeyedWeakReference) queue.poll()) != null) { 6      retainedKeys.remove(ref.key); 7    } 8  } 910  private boolean gone(KeyedWeakReference reference) {11    return !retainedKeys.contains(reference.key);12  }private void removeWeaklyReachableReferences() {
2    // WeakReferences are enqueued as soon as the object to which they point to becomes weakly
3    // reachable. This is before finalization or garbage collection has actually happened.
4    KeyedWeakReference ref;
5    while ((ref = (KeyedWeakReference) queue.poll()) != null) {
6      retainedKeys.remove(ref.key);
7    }
8  }
9
10  private boolean gone(KeyedWeakReference reference{
11    return !retainedKeys.contains(reference.key);
12  }

6、haha

大家有兴趣可以分析下这个分析库的原理。在这里就不深入研究了。

最后把分析的引用链 写入文件中,发通知。

 1  @TargetApi(HONEYCOMB) @Override 2  protected final void onHeapAnalyzed(HeapDump heapDump, AnalysisResult result) { 3    String leakInfo = leakInfo(this, heapDump, result); 4    Log.d("LeakCanary", leakInfo); 5 6    if (!result.leakFound || result.excludedLeak) { 7      afterDefaultHandling(heapDump, result, leakInfo); 8      return; 9    }1011    File leakDirectory = DisplayLeakActivity.leakDirectory(this);12    int maxStoredLeaks = getResources().getInteger(R.integer.__leak_canary_max_stored_leaks);13    File renamedFile = findNextAvailableHprofFile(leakDirectory, maxStoredLeaks);1415    if (renamedFile == null) {16      // No file available.17      Log.e("LeakCanary",18          "Leak result dropped because we already store " + maxStoredLeaks + " leak traces.");19      afterDefaultHandling(heapDump, result, leakInfo);20      return;21    }2223    heapDump = heapDump.renameFile(renamedFile);2425    File resultFile = DisplayLeakActivity.leakResultFile(renamedFile);26    FileOutputStream fos = null;27    try {28      fos = new FileOutputStream(resultFile);29      ObjectOutputStream oos = new ObjectOutputStream(fos);30      oos.writeObject(heapDump);31      oos.writeObject(result);32    } catch (IOException e) {33      Log.e("LeakCanary", "Could not save leak analysis result to disk", e);34      afterDefaultHandling(heapDump, result, leakInfo);35      return;36    } finally {37      if (fos != null) {38        try {39          fos.close();40        } catch (IOException ignored) {41        }42      }43    }4445    PendingIntent pendingIntent =46        DisplayLeakActivity.createPendingIntent(this, heapDump.referenceKey);4748    String contentTitle =49        getString(R.string.__leak_canary_class_has_leaked, classSimpleName(result.className));50    String contentText = getString(R.string.__leak_canary_notification_message);5152    NotificationManager notificationManager =53        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);5455    Notification notification;56    if (SDK_INT < HONEYCOMB) {57      notification = new Notification();58      notification.icon = R.drawable.__leak_canary_notification;59      notification.when = System.currentTimeMillis();60      notification.flags |= Notification.FLAG_AUTO_CANCEL;61      notification.setLatestEventInfo(this, contentTitle, contentText, pendingIntent);62    } else {63      Notification.Builder builder = new Notification.Builder(this) //64          .setSmallIcon(R.drawable.__leak_canary_notification)65          .setWhen(System.currentTimeMillis())66          .setContentTitle(contentTitle)67          .setContentText(contentText)68          .setAutoCancel(true)69          .setContentIntent(pendingIntent);70      if (SDK_INT < JELLY_BEAN) {71        notification = builder.getNotification();72      } else {73        notification = builder.build();74      }75    }76    notificationManager.notify(0xDEAFBEEF, notification);77    afterDefaultHandling(heapDump, result, leakInfo);78  }@TargetApi(HONEYCOMB) @Override
2  protected final void onHeapAnalyzed(HeapDump heapDump, AnalysisResult result) {
3    String leakInfo = leakInfo(this, heapDump, result);
4    Log.d("LeakCanary", leakInfo);
5
6    if (!result.leakFound || result.excludedLeak) {
7      afterDefaultHandling(heapDump, result, leakInfo);
8      return;
9    }
10
11    File leakDirectory = DisplayLeakActivity.leakDirectory(this);
12    int maxStoredLeaks = getResources().getInteger(R.integer.__leak_canary_max_stored_leaks);
13    File renamedFile = findNextAvailableHprofFile(leakDirectory, maxStoredLeaks);
14
15    if (renamedFile == null) {
16      // No file available.
17      Log.e("LeakCanary",
18          "Leak result dropped because we already store " + maxStoredLeaks + " leak traces.");
19      afterDefaultHandling(heapDump, result, leakInfo);
20      return;
21    }
22
23    heapDump = heapDump.renameFile(renamedFile);
24
25    File resultFile = DisplayLeakActivity.leakResultFile(renamedFile);
26    FileOutputStream fos = null;
27    try {
28      fos = new FileOutputStream(resultFile);
29      ObjectOutputStream oos = new ObjectOutputStream(fos);
30      oos.writeObject(heapDump);
31      oos.writeObject(result);
32    } catch (IOException e) {
33      Log.e("LeakCanary""Could not save leak analysis result to disk", e);
34      afterDefaultHandling(heapDump, result, leakInfo);
35      return;
36    } finally {
37      if (fos != null) {
38        try {
39          fos.close();
40        } catch (IOException ignored) {
41        }
42      }
43    }
44
45    PendingIntent pendingIntent =
46        DisplayLeakActivity.createPendingIntent(this, heapDump.referenceKey);
47
48    String contentTitle =
49        getString(R.string.__leak_canary_class_has_leaked, classSimpleName(result.className));
50    String contentText = getString(R.string.__leak_canary_notification_message);
51
52    NotificationManager notificationManager =
53        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
54
55    Notification notification;
56    if (SDK_INT < HONEYCOMB) {
57      notification = new Notification();
58      notification.icon = R.drawable.__leak_canary_notification;
59      notification.when = System.currentTimeMillis();
60      notification.flags |= Notification.FLAG_AUTO_CANCEL;
61      notification.setLatestEventInfo(this, contentTitle, contentText, pendingIntent);
62    } else {
63      Notification.Builder builder = new Notification.Builder(this//
64          .setSmallIcon(R.drawable.__leak_canary_notification)
65          .setWhen(System.currentTimeMillis())
66          .setContentTitle(contentTitle)
67          .setContentText(contentText)
68          .setAutoCancel(true)
69          .setContentIntent(pendingIntent);
70      if (SDK_INT < JELLY_BEAN) {
71        notification = builder.getNotification();
72      } else {
73        notification = builder.build();
74      }
75    }
76    notificationManager.notify(0xDEAFBEEF, notification);
77    afterDefaultHandling(heapDump, result, leakInfo);
78  }

总结

其实沿着源码分析很容易让人无法自拔,所以我们更要跳出来看到本质。

1、监听 Activity 的生命周期,在 onDestory 方法里调用 RefWatcher 的 watch  方法。
watch 方法监控的是 Activity 对象
2、给Activyty 的 Reference 生成唯一性的 key 添加到 retainedKeys 。生成 KeyedWeakReference 对象 ,Activity 的弱引用和 ReferenceQueue 关联。执行 ensureGone 方法。
3、如果 retainedKeys 中没有 该 Reference 的 key 那么就说明没有内存泄漏。
4、如果有,那么 analyze 分析我们 HeadDump 文件。建立导致泄漏的引用链。
5、引用链传递给 APP 进程的 DisplayLeakService,以通知的形式展示出来。

                    

640?wx_fmt=png

                                                               

觉得有用,就给我一个“好看”

640?wx_fmt=gif



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值