爲什麼是1.3版本呢,是因爲之前看過的源碼,有幾點沒說明白的,補充一下。如有錯誤,還請指出來。謝謝
基本使用
-
在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()源碼流程分析
-
核心內容
WeakReference弱引用,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否(這一點與SoftReference不同),都會回收它的內存。由於垃圾回收器是一個優先級很低的線程,因此不一定會很快發現那些只具有弱引用的對象。
WeakReference和ReferenceQueue聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。
@Test public void addition_isCorrect() throws Exception { ReferenceQueue<MyClass> queue = new ReferenceQueue<>(); MyClass m = new MyClass(); // 聲明weakreference WeakReference w = new WeakReference(m,queue); // 斷開強引用 m = null; System.gc(); // 睡眠3秒是因爲,主動調用gc是不一定會立馬執行 Thread.sleep(3000); // 回收後會被加入到queue中,所以queue.poll()出來不爲null,就說明被回收了 while(queue.poll()!=null){ System.out.println("被回收了"); } }
-
大體流程如下:
- 監控最終都是調用了watch(object)
- 給object隨機一個key存儲到 set集合中
- 以objcet爲參數初始化一個KeyedWeakReference引用object
- 開啓線程進行監控、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)); } } //講object從queue隊列中取出來,如果不是空說明已經被GC回收了,就將存儲到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保存下來沒有寫。