LeakCanary 基本使用及源码解析
2017-11-24 本文已影响93人
落魄的安卓开发
之前被问过几次LeakCanary的工作原理,今天追踪代码了解一番,并进行记录方便以后查看。如有错误,还请指出来。谢谢
基本使用
-
在build.gradle中:
dependencies { debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3' }
-
在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()源码流程分析
-
大体流程如下:
- 监控最终都是调用了watch(object)
- 给object随机一个key存储到 set集合中
- 以objcet为参数初始化一个弱引用
- 开启线程进行监控、GC、写dumpheap操作
- 从软引用中poll出它内部的objcet,根据是否为空来清除set中的key
- 最后根据set中是否包含key,判断来进行是否调用GC
- 调用完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保存下来没有写。