新聞中心
OOM 是 Android 開發(fā)中常見的問題,而內(nèi)存泄漏往往是罪魁禍首。

創(chuàng)新互聯(lián)制作網(wǎng)站網(wǎng)頁找三站合一網(wǎng)站制作公司,專注于網(wǎng)頁設(shè)計,網(wǎng)站制作、成都網(wǎng)站設(shè)計,網(wǎng)站設(shè)計,企業(yè)網(wǎng)站搭建,網(wǎng)站開發(fā),建網(wǎng)站業(yè)務(wù),680元做網(wǎng)站,已為上千多家服務(wù),創(chuàng)新互聯(lián)網(wǎng)站建設(shè)將一如既往的為我們的客戶提供最優(yōu)質(zhì)的網(wǎng)站建設(shè)、網(wǎng)絡(luò)營銷推廣服務(wù)!
為了簡單方便的檢測內(nèi)存泄漏,Square 開源了 LeakCanary ,它可以實時監(jiān)測 Activity 是否發(fā)生了泄漏,一旦發(fā)現(xiàn)就會自動彈出提示及相關(guān)的泄漏信息供分析。
本文的目的是試圖通過分析 LeakCanary 源碼來探討它的 Activity 泄漏檢測機制。
LeakCanary 使用方式
為了將 LeakCanary 引入到我們的項目里,我們只需要做以下兩步:
- dependencies {
- debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
- releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
- testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'}public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); if (LeakCanary.isInAnalyzerProcess(this)) { // This process is dedicated to LeakCanary for heap analysis.
- // You should not init your app in this process.
- return;
- }
- LeakCanary.install(this);
- }
- }
可以看出,最關(guān)鍵的就是 LeakCanary.install(this); 這么一句話,正式開啟了 LeakCanary 的大門,未來它就會自動幫我們檢測內(nèi)存泄漏,并在發(fā)生泄漏是彈出通知信息。
從 LeakCanary.install(this); 開始
下面我們來看下它做了些什么?
- public static RefWatcher install(Application application) { return install(application, DisplayLeakService.class,
- AndroidExcludedRefs.createAppDefaults().build());
- }public static RefWatcher install(Application application,
- Class extends AbstractAnalysisResultService> listenerServiceClass,
- ExcludedRefs excludedRefs) { if (isInAnalyzerProcess(application)) { return RefWatcher.DISABLED;
- }
- enableDisplayLeakActivity(application);
- HeapDump.Listener heapDumpListener = new ServiceHeapDumpListener(application, listenerServiceClass);
- RefWatcher refWatcher = androidWatcher(application, heapDumpListener, excludedRefs);
- ActivityRefWatcher.installOnIcsPlus(application, refWatcher); return refWatcher;
- }
首先,我們先看最重要的部分,就是:
- RefWatcher refWatcher = androidWatcher(application, heapDumpListener, excludedRefs);
- ActivityRefWatcher.installOnIcsPlus(application, refWatcher);
先生成了一個 RefWatcher ,這個東西非常關(guān)鍵,從名字可以看出,它是用來 watch Reference 的,也就是用來一個監(jiān)控引用的工具。然后再把 refWatcher 和我們自己提供的 application 傳入到 ActivityRefWatcher.installOnIcsPlus(application, refWatcher); 這句里面,繼續(xù)看。
- public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {
- ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
- activityRefWatcher.watchActivities();
- }
創(chuàng)建了一個 ActivityRefWatcher ,大家應(yīng)該能感受到,這個東西就是用來監(jiān)控我們的 Activity 泄漏狀況的,它調(diào)用 watchActivities() 方法,就可以開始進行監(jiān)控了。下面就是它監(jiān)控的核心原理:
- public void watchActivities() {
- application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
- }
它向 application 里注冊了一個 ActivitylifecycleCallbacks 的回調(diào)函數(shù),可以用來監(jiān)聽 Application 整個生命周期所有 Activity 的 lifecycle 事件。再看下這個 lifecycleCallbacks 是什么?
- 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);
- }
- };
原來它只監(jiān)聽了所有 Activity 的 onActivityDestroyed 事件,當 Activity 被 Destory 時,調(diào)用 ActivityRefWatcher.this.onActivityDestroyed(activity); 函數(shù)。
猜測下,正常情況下,當一個這個函數(shù)應(yīng)該 activity 被 Destory 時,那這個 activity 對象應(yīng)該變成 null 才是正確的。如果沒有變成null,那么就意味著發(fā)生了內(nèi)存泄漏。
因此我們向,這個函數(shù) ActivityRefWatcher.this.onActivityDestroyed(activity); 應(yīng)該是用來監(jiān)聽 activity 對象是否變成了 null。繼續(xù)看。
- void onActivityDestroyed(Activity activity) {
- refWatcher.watch(activity);
- }
- RefWatcher refWatcher = androidWatcher(application, heapDumpListener, excludedRefs);
可以看出,這個函數(shù)把目標 activity 對象傳給了 RefWatcher ,讓它去監(jiān)控這個 activity 是否被正?;厥樟耍粑幢换厥?,則意味著發(fā)生了內(nèi)存泄漏。
RefWatcher 如何監(jiān)控 activity 是否被正?;厥漳?
我們先來看看這個 RefWatcher 究竟是個什么東西?
- public static RefWatcher androidWatcher(Context context, HeapDump.Listener heapDumpListener,
- ExcludedRefs excludedRefs) {
- AndroidHeapDumper heapDumper = new AndroidHeapDumper(context, leakDirectoryProvider);
- heapDumper.cleanup(); int watchDelayMillis = 5000;
- AndroidWatchExecutor executor = new AndroidWatchExecutor(watchDelayMillis); return new RefWatcher(executor, debuggerControl, GcTrigger.DEFAULT, heapDumper,
- heapDumpListener, excludedRefs);
- }
這里面涉及到兩個新的對象: AndroidHeapDumper 和 AndroidWatchExecutor ,前者用來 dump 堆內(nèi)存狀態(tài)的,后者則是用來 watch 一個引用的監(jiān)聽器。具體原理后面再看??傊@里已經(jīng)生成好了一個 RefWatcher 對象了。
現(xiàn)在再看上面 onActivityDestroyed(Activity activity) 里調(diào)用的 refWatcher.watch(activity); ,下面來看下這個最為核心的 watch(activity) 方法,了解它是如何監(jiān)控 activity 是否被回收的。
- private final Set
retainedKeys;public void watch(Object activity, String referenceName) { - String key = UUID.randomUUID().toString();
- retainedKeys.add(key); final KeyedWeakReference reference = new KeyedWeakReference(activity, key, referenceName, queue);
- watchExecutor.execute(new Runnable() { @Override public void run() {
- ensureGone(reference, watchStartNanoTime);
- }
- });
- }final class KeyedWeakReference extends WeakReference
- }
可以看到,它首先把我們傳入的 activity 包裝成了一個 KeyedWeakReference (可以暫時看成一個普通的 WeakReference),然后 watchExecutor 會去執(zhí)行一個 Runnable,這個 Runnable 會調(diào)用 ensureGone(reference, watchStartNanoTime) 函數(shù)。
看這個函數(shù)之前猜測下,我們知道 watch 函數(shù)本身就是用來監(jiān)聽 activity 是否被正?;厥?,這就涉及到兩個問題:
- 何時去檢查它是否回收?
- 如何有效地檢查它真的被回收?
所以我們覺得 ensureGone 函數(shù)本身要做的事正如它的名字,就是確保 reference 被回收掉了,否則就意味著內(nèi)存泄漏。
核心函數(shù):ensureGone(reference) 檢測回收
下面來看這個函數(shù)實現(xiàn):
- void ensureGone(KeyedWeakReference reference, long watchStartNanoTime) {
- removeWeaklyReachableReferences(); if (gone(reference) || debuggerControl.isDebuggerAttached()) { return;
- }
- gcTrigger.runGc();
- removeWeaklyReachableReferences(); if (!gone(reference)) {
- File heapDumpFile = heapDumper.dumpHeap();
- heapdumpListener.analyze( new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
- gcDurationMs, heapDumpDurationMs));
- }
- }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);
- }
- }
這里先來解釋下 WeakReference 和 ReferenceQueue 的工作原理。
1.弱引用 WeakReference
被強引用的對象就算發(fā)生 OOM 也永遠不會被垃圾回收機回收;被弱引用的對象,只要被垃圾回收器發(fā)現(xiàn)就會立即被回收;被軟引用的對象,具備內(nèi)存敏感性,只有內(nèi)存不足時才會被回收,常用來做內(nèi)存敏感緩存器;虛引用則任意時刻都可能被回收,使用較少。
2.引用隊列 ReferenceQueue
我們常用一個 WeakReference
然后再回到上面的代碼。
在一個 activity 傳給 RefWatcher 時會創(chuàng)建一個***的 key 對應(yīng)這個 activity,該key存入一個集合 retainedKeys 中。也就是說,所有我們想要觀測的 activity 對應(yīng)的*** key 都會被放入 retainedKeys 集合中。
基于我們對 ReferenceQueue 的了解,只要把隊列中所有的 reference 取出來,并把對應(yīng) retainedKeys 里的key移除,剩下的 key 對應(yīng)的對象都沒有被回收。
- ensureGone 首先調(diào)用 removeWeaklyReachableReferences 把已被回收的對象的 key 從 retainedKeys 移除,剩下的 key 都是未被回收的對象;
- if
分享標題:帶你學開源項目:LeakCanary-如何檢測Activity是否泄漏
URL分享:http://fisionsoft.com.cn/article/dpjijcg.html


咨詢
建站咨詢
