weakReference在java为弱应用对象,在系统发生gc的时候,被weakReference引用的对象会被回收(必然)。
构造方法如下:
public class WeakReference extends Reference {
public WeakReference(T r) {
super(r, null);
}
public WeakReference(T r, ReferenceQueue super T> q) {
super(r, q);
}
}
其中ReferenceQueue是个队列,这个参数比较重要,在系统发生gc的时候会回收被引用的对象,然后会把WeakReference这个入队到ReferenceQueue中,注意不是被引用的对象,因为它已经被回收了。
我们会在Application中调用静态方法install,其中是通过构建者模式创建了AndroidRefWatcherBuilder对象
public static RefWatcher install(Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
其中DisplayLeakService是个服务(继承IntentService),监听dump的信息并分析日志文件,会执行toast和通知栏。
excludedRefs中排除一些国内厂商的系统泄露问题
最后会执行buildAndInstall
public RefWatcher buildAndInstall() {
RefWatcher refWatcher = build();
if (refWatcher != DISABLED) {
LeakCanary.enableDisplayLeakActivity(context);
ActivityRefWatcher.install((Application) context, refWatcher);
}
return refWatcher;
}
其中ActivityRefWatcher.install最后会调用 ActivityRefWatcher.watchActivities方法
application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
其中lifecycleCallbacks变量就是Activity的回调周期函数,这样就可以监听页面的情况,其中lifecycleCallbacks只对onActivityDestroyed进行处理,也就是页面销毁时候检测
@Override public void onActivityDestroyed(Activity activity) {
ActivityRefWatcher.this.onActivityDestroyed(activity);
}
onActivityDestroyed最终会调用refWatcher的watch方法
void onActivityDestroyed(Activity activity) {
refWatcher.watch(activity);
}
watch源码
public void watch(Object watchedReference, String referenceName) {
if (this == DISABLED) {
return;
}
final long watchStartNanoTime = System.nanoTime();
String key = UUID.randomUUID().toString();
retainedKeys.add(key);
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);
ensureGoneAsync(watchStartNanoTime, reference);
}
retainedKeys它是个Set集合,存放随机key,它和KeyedWeakReference的key中对应,以Activity为例我们可以看出,每个Activty对应一个key和一个弱引用对象。
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
long gcStartNanoTime = System.nanoTime();
long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
//清除已回收的对象
removeWeaklyReachableReferences();
//debug模式直接返回
if (debuggerControl.isDebuggerAttached()) {
return RETRY;
}
//是否回收了
if (gone(reference)) {
return DONE;
}
//手动执行gc
gcTrigger.runGc();
//再清除已回收的对象
removeWeaklyReachableReferences();
if (!gone(reference)) {
long startDumpHeap = System.nanoTime();
long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
File heapDumpFile = heapDumper.dumpHeap();
if (heapDumpFile == RETRY_LATER) {
return RETRY;
}
long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
heapdumpListener.analyze(
new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
gcDurationMs, heapDumpDurationMs));
}
return DONE;
}
//判断retainedKeys是否有未回收的对象
private boolean gone(KeyedWeakReference reference) {
return !retainedKeys.contains(reference.key);
}
//根据queue存在的对象移除retainedKeys中的值
private void removeWeaklyReachableReferences() {
KeyedWeakReference ref;
while ((ref = (KeyedWeakReference) queue.poll()) != null) {
retainedKeys.remove(ref.key);
}
}
确定是否回收,根据弱引用的queue是否有值,如果有则移除retainedKeys中的对象。
步骤:
1.根据弱引用的queue中的对象key执行remove操作 删除retainedKeys集合中的值
2.判断retainedKeys是否有存在该对象,若不存在结束操作
3.手动执行gc
4.再执行1,2操作
5.此时若retainedKeys还有值则可判断存在内存泄漏,执行后续操作
若发生内存泄漏会执行 dumpHeap方法,通过 Debug.dumpHprofData 方法获取heapDumpFile,然后启动服务分析.hrof 最后会使用squaredup的haha库进行堆分析
public static void runAnalysis(Context context, HeapDump heapDump,
Class extends AbstractAnalysisResultService> listenerServiceClass) {
//HeapAnalyzerService是分析核心服务
//listenerServiceClass是通知栏通知
Intent intent = new Intent(context, HeapAnalyzerService.class);
intent.putExtra(LISTENER_CLASS_EXTRA, listenerServiceClass.getName());
intent.putExtra(HEAPDUMP_EXTRA, heapDump);
context.startService(intent);
}