監測記憶體洩漏神兵利器:LeakCanary原始碼分析
1 在全域性Application類中註冊:
LeakCanary.install(this);
點進去看原始碼:
public static RefWatcher install(Application application) { return refWatcher(application)// 1-1 .listenerServiceClass(DisplayLeakService.class)// 1-2 .excludedRefs(AndroidExcludedRefs.createAppDefaults().build())//1-3 .buildAndInstall();// 1-4 和 2-1 }
原始碼分為四部分:
- 1-1refWatcher(application) 建立一個 AndroidRefWatcherBuilder 物件
- 1-2.listenerServiceClass(DisplayLeakService.class) 傳入DisplayLeakService,該Service的主要作用是分析記憶體堆資訊,分析出記憶體洩漏的位置;
-
1-3.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
- 1-3-1AndroidExcludedRefs.createAppDefaults().build() 幫助分析跟蹤洩漏的軌跡的物件
- 1-4.buildAndInstall() 建立RefWatcher物件
2 RefWatcher 監聽記憶體洩漏(1-4中開始):
2-1RefWatcher將全域性的context傳入
public RefWatcher buildAndInstall() { RefWatcher refWatcher = build(); if (refWatcher != DISABLED) { LeakCanary.enableDisplayLeakActivity(context); ActivityRefWatcher.install((Application) context, refWatcher);//重點 2-2 } return refWatcher; }
2-2建立一個ActivityRefWatcher() 物件
public static void install(Application application, RefWatcher refWatcher) { new ActivityRefWatcher(application, refWatcher).watchActivities(); }
2-3 ActivityRefWather物件中的重點方法監聽Activity的生命週期,在Activity銷燬時,呼叫RefWatcher的方法:
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);//重點呼叫 2-4 } };
2-4 ActivityRefWatcher.this.onActivityDestroyed(activity)將Activity新增到監測佇列中:
void onActivityDestroyed(Activity activity) { refWatcher.watch(activity); }
public void watch(Object watchedReference) { watch(watchedReference, ""); }
3watch()方法:將Activity封裝為弱引用物件,檢視是否被回收
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);//重點3-1 ensureGoneAsync(watchStartNanoTime, reference);// 重點 3-2 }
- 3-1 通過例項一個帶有鍵值的弱引用 KeyedWeakReference,將Activity唯一標識;
- 3-2 開啟一個執行緒,開始監測該Activity是否被回收,在gc後會呼叫:
private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) { watchExecutor.execute(new Retryable() { @Override public Retryable.Result run() { return ensureGone(reference, watchStartNanoTime);//4-1 } }); }
4 監測分析的最重點方法 ensureGone()
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) { long gcStartNanoTime = System.nanoTime(); long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime); //gc結束的時間 removeWeaklyReachableReferences();// 4-1 if (debuggerControl.isDebuggerAttached()) { // The debugger can create false leaks. return RETRY; } if (gone(reference)) {// 4-2 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) { // Could not dump the heap. return RETRY; } long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap); heapdumpListener.analyze( new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs, gcDurationMs, heapDumpDurationMs)); } return DONE; }
- 4-1removeWeaklyReachableReferences():將存入到ReferenceQueue<Object>queue這個佇列中的、現在不為空的,將其對應的鍵值消除,剩下的就是為空的引用;
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); } }
-
4-2gone(reference) :當前 retainedKeys(是Set<String>型別) 中,已經沒有改Activity對應的引用了,證明在4-1中,已經被移除;也證明了在引用佇列queue中,該Activity不為空;
該ReferenceQueue<Object>queue的作用是:每次WeakReference所指向的物件被GC後,這個弱引用都會被放入這個與之相關聯的ReferenceQueue佇列中。所以在佇列中不為空的Activity就是被回收掉的Activity。
private boolean gone(KeyedWeakReference reference) { return !retainedKeys.contains(reference.key); }
-
4-3引用佇列ReferenceQueue原始碼分析 :
ofollow,noindex">https://blog.csdn.net/Jesministrator/article/details/78786162