ReferenceQueueLeakCanary工具实现的最主要的原理就是利用了Java的ReferenceQueue类特性。
1 2 Object obj = new Object(); Ref ref = new Ref(obj);
上面的代码是一个典型的强引用使用场景,如果 ref 没有被系统GC回收,那 obj这个对象是肯定不会被系统GC回收的。 在Android中的内存泄漏大部分都是上面这种情况导致的,所以为了解决这种情况,我们一般会在Ref类中使用若引用持有obj对象,也就是常见的WeakReference类,使用若引用的好处就是,当ref还没被回收的情况下,如果obj对象占用内存过大,系统GC会直接将obj对象进行回收。当GC回收了obj对象后可能需要通知用户线程进行额外的处理操作,这个时候就需要一个引用队列。ReferenceQueue即这样的一个对象,当一个obj被GC回收后,其相应的包装类,即ref对象会被放入queue中。我们可以从queue中获取到相应的对象信息,同时进行额外的处理。比如反向操作,数据清理等。
LeakCanary实现流程那么LeakCanary是怎么使用这个特性的呢,LeakCanary检测内存泄漏的一个大致流程如下:
Application中调用LeakCanary.install(this)进行注册
install方法中会注册一个Application.ActivityLifecycleCallbacks,在回调的onActivityDestroyed(Activity activity)方法中检测当前Activity是否被GC回收。
在onActivityDestroyed(Activity activity)中检测的方法就是创建一个 Activity的弱引用对象。
判断ReferenceQueue中是否有这个弱引用对象,如果有则说明当前这个Activity已经被GC回收了。
如果没有则主动调用一次系统的GC,等待100ms后再查看一次。
如果ReferenceQueue中依旧没有这个弱引用对象,说明当前Activity没有被系统GC回收。
没有被系统回收就调用 Debug.dumpHprofData(dumpHproFilePath)方法生成内存使用快照文件。
代码分析 LeakCanary.install(this)1 2 3 4 5 6 public static RefWatcher install (Application application) { return refWatcher(application) .listenerServiceClass(DisplayLeakService.class ) //状态栏通知service .excludedRefs (AndroidExcludedRefs .createAppDefaults ().build ()) //过滤一些系统bug .buildAndInstall () ; }
buildAndInstall()1 2 3 4 5 6 7 8 public RefWatcher buildAndInstall () { RefWatcher refWatcher = build(); if (refWatcher != DISABLED) { LeakCanary.enableDisplayLeakActivity(context); ActivityRefWatcher.install((Application) context, refWatcher); } return refWatcher; }
buildAndInstall()方法中主要有三步操作:
创建RefWatcher类
设置桌面图标可见,就是我们使用LeakCanary的时候桌面多出的那个入口图标,其内部是调用了PackageManager的setComponentEnabledSetting方法设置DisplayLeakActivity.class为入口Activity
1 2 3 4 5 6 7 8 public static void setEnabledBlocking (Context appContext, Class<?> componentClass, boolean enabled) { ComponentName component = new ComponentName(appContext, componentClass); PackageManager packageManager = appContext.getPackageManager(); int newState = enabled ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DISABLED; packageManager.setComponentEnabledSetting(component, newState, DONT_KILL_APP); }
第三步就开始注册Activity的监听
ActivityRefWatcher.install()1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public final class ActivityRefWatcher { public static void install (Application application, RefWatcher refWatcher) { new ActivityRefWatcher(application, refWatcher).watchActivities(); } private final Application.ActivityLifecycleCallbacks lifecycleCallbacks = new Application.ActivityLifecycleCallbacks() { @Override public void onActivityCreated (Activity activity, Bundle savedInstanceState) { } @Override public void onActivityStarted (Activity activity) { } @Override public void onActivityResumed (Activity activity) { } @Override public void onActivityPaused (Activity activity) { } @Override public void onActivityStopped (Activity activity) { } @Override public void onActivitySaveInstanceState (Activity activity, Bundle outState) { } @Override public void onActivityDestroyed (Activity activity) { ActivityRefWatcher.this .onActivityDestroyed(activity); } }; private final Application application; private final RefWatcher refWatcher; void onActivityDestroyed (Activity activity) { refWatcher.watch(activity); } public void watchActivities () { stopWatchingActivities(); application.registerActivityLifecycleCallbacks(lifecycleCallbacks); } }
ActivityRefWatcher类中在Application中注册一个Application.ActivityLifecycleCallbacks,然后在onActivityDestroyed(Activity activity)回调方法中调用refWatcher.watch(activity);开始进行检测。
refWatcher.watch(activity)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public void watch (Object watchedReference) { watch(watchedReference, "" ); } public void watch (Object watchedReference, String referenceName) { if (this == DISABLED) { return ; } checkNotNull(watchedReference, "watchedReference" ); checkNotNull(referenceName, "referenceName" ); final long watchStartNanoTime = System.nanoTime(); String key = UUID.randomUUID().toString(); retainedKeys.add(key); final KeyedWeakReference reference = new KeyedWeakReference(watchedReference, key, referenceName, queue); ensureGoneAsync(watchStartNanoTime, reference); }
watch()方法中主要有两步操作:
生成一个随机数Key并存入一个Set集合中
创建一个弱引用对象KeyedWeakReference
接下来看ensureGoneAsync()方法
ensureGoneAsync()1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 private void ensureGoneAsync (final long watchStartNanoTime, final KeyedWeakReference reference) { watchExecutor.execute(new Retryable() { @Override public Retryable.Result run () { return ensureGone(reference, watchStartNanoTime); } }); } @SuppressWarnings ("ReferenceEquality" ) Retryable.Result ensureGone (final KeyedWeakReference reference, final long watchStartNanoTime) { long gcStartNanoTime = System.nanoTime(); long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime); removeWeaklyReachableReferences(); if (debuggerControl.isDebuggerAttached()) { return RETRY; } if (gone(reference)) { return DONE; } gcTrigger.runGc(); removeWeaklyReachableReferences(); if (!gone(reference)) { long startDumpHeap = System.nanoTime(); long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime); File heapDumpFile = heapDumper.dumpHeap(); if (heapDumpFile == RETRY_LATER) { return RETRY; } long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap); heapdumpListener.analyze( new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs, gcDurationMs, heapDumpDurationMs)); } return DONE; } private boolean gone (KeyedWeakReference reference) { return !retainedKeys.contains(reference.key); } private void removeWeaklyReachableReferences () { KeyedWeakReference ref; while ((ref = (KeyedWeakReference) queue.poll()) != null ) { retainedKeys.remove(ref.key); } }
ensureGoneAsync()会调用ensureGone()方法,在ensureGone()方法中进行下面几步操作:
调用removeWeaklyReachableReferences()检测弱引用对象是否在ReferenceQueue队列中,如果在说明对象已回收,同时删除Set集合中的Key
判断Set集合中是否存在Key,若依然存在,说明对象未回收
调用gcTrigger.runGc();,其内部调用系统GC,并等待100ms
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public interface GcTrigger { GcTrigger DEFAULT = new GcTrigger() { @Override public void runGc () { Runtime.getRuntime().gc(); enqueueReferences(); System.runFinalization(); } private void enqueueReferences () { try { Thread.sleep(100 ); } catch (InterruptedException e) { throw new AssertionError(); } } }; void runGc () ; }
再次调用removeWeaklyReachableReferences()方法进行检测
若依然未回收对象,则开始生产内存分析文件。
其他 LeakCanary默认分析的是Activity的内存泄漏,如果我们需要对Fragment进行内存泄漏分析,可以自己进行调用。
LeakCanary.install(this)返回的是一个RefWatcher对象,我们可以在Application中定义一个静态常量持有这个对象
1 2 3 4 5 6 7 8 9 10 class BaseApplication : MultiDexApplication () { companion object { var refWatcher:RefWatcher? = null } override fun onCreate () { super .onCreate() refWatcher = LeakCanary.install(this ) } }
然后在项目的BaseFragment的onDestroy()方法中调用
1 2 3 4 override fun onDestroy () { super .onDestroy() BaseApplication.refWatcher?.watch(this ) }