github地址:LeakCanary
使用很简单
In your build.gradle
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'
// Optional, if you use support library fragments:
debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3'
}
In your Application class:
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);
// Normal app init code...
}
}
检查内存泄露的流程
由于在Android api 14的以上,才提供ActivityLifecycleCallbacks类,所以在14以下可以通过在Activity的onDestory方法中,调用ReWatch对象的watch方法来实现内存检查。
((ExampleApplication)getApplicationInfo()).getRefWatcher().watch(this);
简单说下流程
- 通过监听activity 的生命周期。
- 创建关联activity的KeyedWeakReference和ReferenceQueue对象,并且创建一个集合retainedKeys,该集合用来中保存当前activity的key值(key值是指区分每个activity的标识符),判断当前activity是否发生泄漏的关键,KeyedWeakReference,ReferenceQueue这俩个对象的主要作用是当activity销毁时,相关连的KeyedWeakReference引用也将消失,那么在ReferenceQueue中可以找到activity的引用对象。然后在retainedKeys中移除该activity,如果在retainedKeys中找不到当前activity的软引用对象,说明有内存泄露,然后通过分析hprof 文件 。
- 分析完成之后发送通知到通知栏,
下面分析下具体的实现:
public static @NonNull RefWatcher install(@NonNull Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
通过链式调用,refWatcher(application) 方法返回一个AndroidRefWatcherBuilder对象。
public static @NonNull AndroidRefWatcherBuilder refWatcher(@NonNull Context context) {
return new AndroidRefWatcherBuilder(context);
}
AndroidRefWatcherBuilder ,是RefWatcherBuilder的子类,再看listenerServiceClass(DisplayLeakService.class),
/**
* 设置一个自定义的AbstractAnalysisResultService 去监听分析结果,
* Sets a custom {@link AbstractAnalysisResultService} to listen to analysis results. This
* overrides any call to {@link #heapDumpListener(HeapDump.Listener)}.
*/
public @NonNull AndroidRefWatcherBuilder listenerServiceClass(
@NonNull Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
//listenerServiceClass 是不是DisplayLeakService 的子类或者接口
enableDisplayLeakActivity = DisplayLeakService.class.isAssignableFrom(listenerServiceClass);
return heapDumpListener(new ServiceHeapDumpListener(context, listenerServiceClass));
}
enableDisplayLeakActivity表示是否默认显示泄露的activity,ServiceHeapDumpListener用来分析生成的hprof文件。excludedRefs(AndroidExcludedRefs.createAppDefaults().build()),排除掉Android系统层面导致的引用,这里有一些是由于厂商导致的,还有一些事系统本身就存在的,这个我们不用管的泄露问题。
最后再来看看 buildAndInstall()方法,
/**
* Creates a {@link RefWatcher} instance and makes it available through {@link
* LeakCanary#installedRefWatcher()}.
*
* Also starts watching activity references if {@link #watchActivities(boolean)} was set to true.
*
* @throws UnsupportedOperationException if called more than once per Android process.
*/
public @NonNull RefWatcher buildAndInstall() {
//表示buildAndInstall 这个方法只能调用一次,因为下面已经重新赋值了的,
if (LeakCanaryInternals.installedRefWatcher != null) {
throw new UnsupportedOperationException("buildAndInstall() should only be called once.");
}
//构建RefWatcher
RefWatcher refWatcher = build();
if (refWatcher != DISABLED) {
//开启一个组件,(动态注册一个DisplayLeakActivity)
if (enableDisplayLeakActivity) {
LeakCanaryInternals.setEnabledAsync(context, DisplayLeakActivity.class, true);
}
//将activity的生命周期和refWatcher对象关联起来
if (watchActivities) {
ActivityRefWatcher.install(context, refWatcher);
}
}
//重新赋值
LeakCanaryInternals.installedRefWatcher = refWatcher;
return refWatcher;
}
主要看构建 build()方法
/** Creates a {@link RefWatcher}. */
public final RefWatcher build() {
if (isDisabled()) {
return RefWatcher.DISABLED;
}
//排除可以忽略的泄漏路径
if (heapDumpBuilder.excludedRefs == null) {
heapDumpBuilder.excludedRefs(defaultExcludedRefs());
}
//解析完 hprof 文件,进行回调,并通知 DisplayLeakService 弹出提醒
HeapDump.Listener heapDumpListener = this.heapDumpListener;
if (heapDumpListener == null) {
heapDumpListener = defaultHeapDumpListener();
}
//判断是否处于调试模式,调试模式中不会进行内存泄漏检测
DebuggerControl debuggerControl = this.debuggerControl;
if (debuggerControl == null) {
debuggerControl = defaultDebuggerControl();
}
//dump 内存泄漏处的 heap 信息,写入 hprof 文件
HeapDumper heapDumper = this.heapDumper;
if (heapDumper == null) {
heapDumper = defaultHeapDumper();
}
//线程控制器,在 onDestroy() 之后并且主线程空闲时执行内存泄漏检测
WatchExecutor watchExecutor = this.watchExecutor;
if (watchExecutor == null) {
watchExecutor = defaultWatchExecutor();
}
// 用于 GC,watchExecutor 首次检测到可能的内存泄漏,会主动进行 GC,GC 之后会再检测一次,仍然泄漏的判定为内存泄漏,进行后续操作
GcTrigger gcTrigger = this.gcTrigger;
if (gcTrigger == null) {
gcTrigger = defaultGcTrigger();
}
if (heapDumpBuilder.reachabilityInspectorClasses == null) {
heapDumpBuilder.reachabilityInspectorClasses(defaultReachabilityInspectorClasses());
}
return new RefWatcher(watchExecutor, debuggerControl, gcTrigger, heapDumper, heapDumpListener,
heapDumpBuilder);
}
将RefWatcher 和activity关联起来ActivityRefWatcher.install(context, 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 final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
new ActivityLifecycleCallbacksAdapter() {
@Override public void onActivityDestroyed(Activity activity) {
refWatcher.watch(activity);
}
};
可以看到在生命周期onActivityDestroyed 时,回调refwatcher调用watch方法。查看watch方法
/**
* Identical to {@link #watch(Object, String)} with an empty string reference name.
*
* @see #watch(Object, String)
*/
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();
//保证key 的唯一性
String key = UUID.randomUUID().toString();
//添加到set集合
retainedKeys.add(key);
//创建KeyedWeakReference对象
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);
ensureGoneAsync(watchStartNanoTime, reference);
}
这就是前面说的KeyedWeakReference和queue对象。再看ensureGoneAsync(watchStartNanoTime, reference)方法
private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
watchExecutor.execute(new Retryable() {
@Override public Retryable.Result run() {
return ensureGone(reference, watchStartNanoTime);
}
});
}
@SuppressWarnings("ReferenceEquality") // Explicitly checking for named null.
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
long gcStartNanoTime = System.nanoTime();
long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
//// 移除已经被回收的引用
removeWeaklyReachableReferences();
if (debuggerControl.isDebuggerAttached()) {
// The debugger can create false leaks.
return RETRY;
}
// 判断 reference,即 activity 是否内回收了,若被回收了,直接返回
if (gone(reference)) {
return DONE;
}
// 调用 gc 方法进行垃圾回收
gcTrigger.runGc();
// 移除已经被回收的引用
removeWeaklyReachableReferences();
// activity 还没有被回收,证明发生内存泄露
if (!gone(reference)) {
long startDumpHeap = System.nanoTime();
long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
// dump heap,并生成相应的 hprof 文件
File heapDumpFile = heapDumper.dumpHeap();
// dump the heap 失败的时候
if (heapDumpFile == RETRY_LATER) {
// Could not dump the heap.
return RETRY;
}
long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
.referenceName(reference.name)
.watchDurationMs(watchDurationMs)
.gcDurationMs(gcDurationMs)
.heapDumpDurationMs(heapDumpDurationMs)
.build();
heapdumpListener.analyze(heapDump);
}
return DONE;
}
这里的 watchExecutor是在AndroidRefWatcherBuilder生产的。
@Override protected @NonNull WatchExecutor defaultWatchExecutor() {
return new AndroidWatchExecutor(DEFAULT_WATCH_DELAY_MILLIS);
}
具体的实现execute()方法
@Override public void execute(@NonNull Retryable retryable) {
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
//如果是主线程就等到空闲
waitForIdle(retryable, 0);
} else {
//非主线程等到空闲
postWaitForIdle(retryable, 0);
}
}
//在主线程中更新
private void postWaitForIdle(final Retryable retryable, final int failedAttempts) {
mainHandler.post(new Runnable() {
@Override public void run() {
waitForIdle(retryable, failedAttempts);
}
});
}
private void waitForIdle(final Retryable retryable, final int failedAttempts) {
// This needs to be called from the main thread.
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override public boolean queueIdle() {
postToBackgroundWithDelay(retryable, failedAttempts);
return false;
}
});
}
最后发现都是调用的postToBackgroundWithDelay()这个方法,postToBackgroundWithDelay()这个方法是一个根据返回结果判断是否重复执行的方法,类似递归。
// 取 Math.pow(2, failedAttempts), maxBackoffFactor 的最小值,maxBackoffFactor = Long.MAX_VALUE / 5,
// 第一次执行的时候 failedAttempts 是 0 ,所以 exponentialBackoffFactor 是1
long exponentialBackoffFactor = (long) Math.min(Math.pow(2, failedAttempts), maxBackoffFactor);
// initialDelayMillis 的默认值是 5
long delayMillis = initialDelayMillis * exponentialBackoffFactor;
Log.e("info","exponentialBackoffFactor-->"+exponentialBackoffFactor+"delayMillis-->"+delayMillis);
// 所以第一次延迟执行的时候是 5s,若
backgroundHandler.postDelayed(new Runnable() {
@Override public void run() {
Retryable.Result result = retryable.run();
if (result == RETRY) {
// 过 result == RETRY,再次调用 postWaitForIdle,下一次的 delayMillis= 上一次的 delayMillis *2;
postWaitForIdle(retryable, failedAttempts + 1);
}
}
}, delayMillis);
}
看下retryable.run()方法 。执行的正是ensureGone(reference, watchStartNanoTime)方法。判断其返回结果,看是否需要重复执行postWaitForIdle(retryable, failedAttempts + 1)。ensureGone()方法的执行原理就是整个leakcarany方法的检查泄漏的主要逻辑点,首先检查将ReferenceQueue˙中的软引用移除,再调用gc方法进行垃圾回收,在此将ReferenceQueue的软引用移除,如果还存在无法销毁的引用,那证明会导致内存泄漏。