一、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原理
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获取结果,然后调用回调通知。