原创作者: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}
超级简单的配置和使用方式。最后就会得出以下的事例说明。
二、准备工作
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 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;
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,以通知的形式展示出来。
觉得有用,就给我一个“好看”