当前位置: 首页 > 工具软件 > LeakCanary > 使用案例 >

LeakCanary

闻人修平
2023-12-01

一、LeakCanary

       LeakCanary由Square开源的一款轻量第三方内存泄漏检测工具

1、LeakCanary的使用

 (1)在app  build.gradle中加入引用

debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'

(2)在application中初始化

@Override
public void onCreate() {
    super.onCreate();
    LeakCanary.install(this);
}

2、LeakCanary监控那些本该回收的对象,如fragment

(1)获取RefWatcher

private RefWatcher refWatcher;
public static RefWatcher getRefWatcher(Context context) {
    Lantian application = (Lantian) context.getApplicationContext();
    return application.refWatcher;
}

@Override
public void onCreate() {
    super.onCreate();
    refWatcher = LeakCanary.install(this);
    initUtils();
}

(2)在fragment中的onDestory方法中使用

@Override
protected void onDestroy() {
    super.onDestroy();
    RefWatcher refWatcher = Lantian.getRefWatcher(this);
    refWatcher.watch(this);
}

2、注意事项

     应用需要写SD权限,因为LeakCanary需要生成Hprof文件,保存在SD卡里面

3、LeakCanary原理

  • 当Activity/Fragment执行完onDestory生命周期,它放在一个WeakReference
  • 这个WeakReference关联到一个ReferenceQueue
  • 查看ReferenceQueue是否存在Anctivity的引用
  • 如果不存在,则这个Activity发生了泄漏,Dump出heap信息,然后再去分析泄漏路径。

 4、源码解析

(1)前奏铺垫

         API14之后,在Application类中,提供了一个接口,可以监听activity的生命周期,这个接口就是ActivityLifecycleCallback

public interface ActivityLifecycleCallbacks {
    void onActivityCreated(Activity activity, Bundle savedInstanceState);
    void onActivityStarted(Activity activity);
    void onActivityResumed(Activity activity);
    void onActivityPaused(Activity activity);
    void onActivityStopped(Activity activity);
    void onActivitySaveInstanceState(Activity activity, Bundle outState);
    void onActivityDestroyed(Activity activity);
}

application中定义了一个集合,元素就是activityLifecycleCallback,

private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
            new ArrayList<ActivityLifecycleCallbacks>();

通过方法registerActivityLifecycleCallbacks注册,

public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
    synchronized (mActivityLifecycleCallbacks) {
       mActivityLifecycleCallbacks.add(callback);
    }
}

通过unRegisterActivityLifecycleCallbacks反注册

public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
    synchronized (mActivityLifecycleCallbacks) {
       mActivityLifecycleCallbacks.remove(callback);
    }
}

 

(1)初始化install方法

@NonNull
public static RefWatcher install(@NonNull Application application) {
return ((AndroidRefWatcherBuilder)refWatcher(application)
       .listenerServiceClass(DisplayLeakService.class)
       .excludedRefs(AndroidExcludedRefs.createAppDefaults().build()))
       .buildAndInstall();
}

public static @NonNull AndroidRefWatcherBuilder refWatcher(@NonNull Context context) {
    return new AndroidRefWatcherBuilder(context);
}

    首先创建一个AndroidRefWatcherBuilder,这里是buidl设计模式,配置参数listenerServiceClass(对解析结果做回调监听),excludedRefs(设置需要过滤的内存泄漏),最后调用buildAndInstal方法,返回一个refWatcher对象。

分支一:配置listenerSercieClass,使用的是SercviceHeapDumpListener,后面要使用

@NonNull
public AndroidRefWatcherBuilder listenerServiceClass(@NonNull Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
        return (AndroidRefWatcherBuilder)this.heapDumpListener(
new ServiceHeapDumpListener(this.context, listenerServiceClass));
}

   回到主干,builderAndinstall方法源码如下:

if (LeakCanaryInternals.installedRefWatcher != null) {
            throw new UnsupportedOperationException("buildAndInstall() should only be called once.");
        } else {
            RefWatcher refWatcher = this.build();
            if (refWatcher != RefWatcher.DISABLED) {
                LeakCanaryInternals.setEnabledAsync(this.context, DisplayLeakActivity.class, true);
                if (this.watchActivities) {
                    ActivityRefWatcher.install(this.context, refWatcher);
                }

                if (this.watchFragments) {
                    Helper.install(this.context, refWatcher);
                }
            }

            LeakCanaryInternals.installedRefWatcher = refWatcher;
            return refWatcher;
        }

ActivityRefWatcher的install方法,里面会初始化ActivityRefWatcher对象,构造函数为refWatcher对象;这里对系统提供的ActivityLifecycleCallback进行封装,因为我们只需要onActivityDestoryed的回调,在我们的项目中activity调用onDestory方法时,ActivityLifecycleCallback会监听到,然后会调用自己的方法onActivityDestoryed,里面就是通过watch方法实现对activity进行观测。

private final ActivityLifecycleCallbacks lifecycleCallbacks = new ActivityLifecycleCallbacksAdapter() {
        public void onActivityDestroyed(Activity activity) {
            ActivityRefWatcher.this.refWatcher.watch(activity);
        }
    };
    private final Application application;
    private final RefWatcher refWatcher;

    public static void installOnIcsPlus(@NonNull Application application, @NonNull RefWatcher refWatcher) {
        install(application, refWatcher);
    }

    public static void install(@NonNull Context context, @NonNull RefWatcher refWatcher) {
        Application application = (Application)context.getApplicationContext();
        ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
        application.registerActivityLifecycleCallbacks(activityRefWatcher.lifecycleCallbacks);
    }

    private ActivityRefWatcher(Application application, RefWatcher refWatcher) {
        this.application = application;
        this.refWatcher = refWatcher;
    }

    public void watchActivities() {
        this.stopWatchingActivities();
        this.application.registerActivityLifecycleCallbacks(this.lifecycleCallbacks);
    }

    public void stopWatchingActivities() {
        this.application.unregisterActivityLifecycleCallbacks(this.lifecycleCallbacks);
    }

回到refWatcher的watch方法:我们调用的是一个参数的方法,间接调用的是两个参数的方法

public void watch(Object watchedReference) {
   this.watch(watchedReference, "");
}

public void watch(Object watchedReference, String referenceName) {
   if (this != DISABLED) {
            Preconditions.checkNotNull(watchedReference, "watchedReference");
            Preconditions.checkNotNull(referenceName, "referenceName");
            long watchStartNanoTime = System.nanoTime();
            String key = UUID.randomUUID().toString();
            this.retainedKeys.add(key);
            KeyedWeakReference reference = new KeyedWeakReference(
            watchedReference, key, referenceName, this.queue);
            this.ensureGoneAsync(watchStartNanoTime, reference);
        }
}

 首先refWatcher有个成员变量是ReferenceQueue,我们把activity封装成keyedWeakReference,keyedWeakReference是WeakReference的子类,这里就不详细介绍了,接着调用ensureGoneAsync方法,把检测activity的开始时间和weakReference传入。

ensureGoneAsync方法,里面有线程池,开启一个新任务,run方法中执行的是ensureGone方法。

private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
        this.watchExecutor.execute(new Retryable() {
            public Result run() {
                return RefWatcher.this.ensureGone(reference, watchStartNanoTime);
            }
        });
    }
ensureGone方法如下
Result ensureGone(KeyedWeakReference reference, long watchStartNanoTime) {
        long gcStartNanoTime = System.nanoTime();
        long watchDurationMs = TimeUnit.NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
        this.removeWeaklyReachableReferences();
        if (this.debuggerControl.isDebuggerAttached()) {
            return Result.RETRY;
        } else if (this.gone(reference)) {
            return Result.DONE;
        } else {
            this.gcTrigger.runGc();
            this.removeWeaklyReachableReferences();
            if (!this.gone(reference)) {
                long startDumpHeap = System.nanoTime();
                long gcDurationMs = TimeUnit.NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
                File heapDumpFile = this.heapDumper.dumpHeap();
                if (heapDumpFile == HeapDumper.RETRY_LATER) {
                    return Result.RETRY;
                }

                long heapDumpDurationMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
                HeapDump heapDump = this.heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key).referenceName(reference.name).watchDurationMs(watchDurationMs).gcDurationMs(gcDurationMs).heapDumpDurationMs(heapDumpDurationMs).build();
                this.heapdumpListener.analyze(heapDump);
            }

            return Result.DONE;
        }
    }

首先移除引用队列中的引用,因为这些对象都已经被正常回收了,没有造成泄露,触发GC,然后在清除一次引用队列,我们判断当前对象的引用是否还存在,如果还存在,则这个对象发生了泄露,然后生成heapDump文件,调用HeapdumpListener的analyze方法,HeapdumpListener这个对象在我们初始化refWatcher时已赋值ServiceHeapDumpListener,我们看它的analyze方法。

public void analyze(@NonNull HeapDump heapDump) {
   Preconditions.checkNotNull(heapDump, "heapDump");
   HeapAnalyzerService.runAnalysis(this.context, heapDump, this.listenerServiceClass);
}

调用了HeapAnalyzerService的静态方法runAnalysis,HeapAnalyzerService继承ForegroundService,ForegroundService继承IntentService,runAnalysis是开启了服务

 public static void runAnalysis(Context context, HeapDump heapDump,
 Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
        LeakCanaryInternals.setEnabledBlocking(context, HeapAnalyzerService.class, true);
        LeakCanaryInternals.setEnabledBlocking(context, listenerServiceClass, true);
        Intent intent = new Intent(context, HeapAnalyzerService.class);
        intent.putExtra("listener_class_extra", listenerServiceClass.getName());
        intent.putExtra("heapdump_extra", heapDump);
        ContextCompat.startForegroundService(context, intent);
    }

因为 HeapAnalyzerService是IntentService类,最后调到了onHandleIntentInForeground方法

protected void onHandleIntentInForeground(@Nullable Intent intent) {
        if (intent == null) {
            CanaryLog.d("HeapAnalyzerService received a null intent, ignoring.", new Object[0]);
        } else {
            String listenerClassName = intent.getStringExtra("listener_class_extra");
            HeapDump heapDump = (HeapDump)intent.getSerializableExtra("heapdump_extra");
            HeapAnalyzer heapAnalyzer = new HeapAnalyzer(heapDump.excludedRefs, this, heapDump.reachabilityInspectorClasses);
            AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey, heapDump.computeRetainedHeapSize);
            AbstractAnalysisResultService.sendResultToListener(this, listenerClassName, heapDump, result);
        }
    }

通过heapAnalyzer的checkForLeak获取结果,然后调用回调通知。

 类似资料:

相关阅读

相关文章

相关问答