Reference主要负责内存的一个状态,Reference类把内存分为四种状态:
引用队列,在对象的可达性更改后,垃圾回收器将已注册的引用对象添加到队列中。
举个例子
检测一个对象是否被回收,可以使用Reference + ReferenceQueue
创建一个引用队列
ReferenceQueue queue = new ReferenceQueue();
// 创建弱引用,此时状态为Active,并且Reference.pending为空,当前Reference.queue = 上面创建的queue,并且next=null
WeakReference reference = new WeakReference(new Object(), queue);
System.out.println(reference);
// 当GC执行后,由于是虚引用,所以回收该object对象,并且置于pending上,此时reference的状态为PENDING
System.gc();
/* ReferenceHandler从pending中取下该元素,并且将该元素放入到queue中,此时Reference状态为ENQUEUED,Reference.queue = ReferenceENQUEUED */
/* 当从queue里面取出该元素,则变为INACTIVE,Reference.queue = Reference.NULL */
Reference reference1 = queue.remove();
System.out.println(reference1);
使用上只需在Application.onCreate()中调用一句LeakCanary.install(this)即可。
进入install方法
public static RefWatcher install(Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
标准的建造者模式
最后的buildAndInstall()方法
public RefWatcher buildAndInstall() {
if (LeakCanaryInternals.installedRefWatcher != null) {
throw new UnsupportedOperationException("buildAndInstall() should only be called once.");
}
//调用build方法构造
RefWatcher refWatcher = build();
if (refWatcher != DISABLED) {
LeakCanary.enableDisplayLeakActivity(context);
if (watchActivities) {
//传入build好的RefWatch,调用静态方法进行install
ActivityRefWatcher.install((Application) context, refWatcher);
}
}
LeakCanaryInternals.installedRefWatcher = refWatcher;
return refWatcher;
}
完全是build设计模式,构造出一个RefWatcher
接下来进入install((Application) context, refWatcher)
public static void install(Application application, RefWatcher refWatcher) {
new ActivityRefWatcher(application, refWatcher).watchActivities();
}
构造ActivityRefWatcher并调用watchActivities()监控activity
那么,我们想想作为第三方应用来说,如何监控应用内的每一个Activity?
可以通过系统提供给我们的接口ActivityLifecycleCallbacks,该接口的回调方法与activity生命周期回调方法对应,每当有activity创建或销毁时,可以通过回调方法通知外部
watchActivities方法
public void watchActivities() {
// Make sure you don't get installed twice.
stopWatchingActivities();
application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
}
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);
}
};
onActivityDestory方法:
void onActivityDestroyed(Activity activity) {
refWatcher.watch(activity);
}
交给watcher处理。到此,完成了第一步:监听activity销毁信息.
接下来研究watch()方法是如何判断activity是否泄漏的
public void watch(Object watchedReference, String referenceName) {
if (this == DISABLED) {
return;
}
checkNotNull(watchedReference, "watchedReference");
checkNotNull(referenceName, "referenceName");
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);
}
这里将activity、唯一生成的key、还有queue(是一个ReferenceQueue) 构造一个KeyedWeakReference。并将key值存入retainKeys中保管。该类是WeakReference的子类,如下:
final class KeyedWeakReference extends WeakReference
public final String key;
public final String name;
KeyedWeakReference(Object referent, String key, String name,
ReferenceQueue
super(checkNotNull(referent, "referent"), checkNotNull(referenceQueue, "referenceQueue"));
this.key = checkNotNull(key, "key");
this.name = checkNotNull(name, "name");
}
}
这里,我们将activity包装弱引用,并添加了referenceQueue,那么当该activity被GC回收时,我们就可以从referenceQueue中获取该activity的reference。
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
long gcStartNanoTime = System.nanoTime();
long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
//将已被回收的activity对象的keyedWeakReference的key值从retainedKeys中删除,以达到
//过滤目的
removeWeaklyReachableReferences();
if (debuggerControl.isDebuggerAttached()) {
// The debugger can create false leaks.
return RETRY;
}
//如果retainedKeys中不存在reference,说明它已经被回收,返回
if (gone(reference)) {
return DONE;
}
//手动调用GC
gcTrigger.runGc();
//再次过滤
removeWeaklyReachableReferences();
//若retainedKeys中还存在该reference(还没有被滤掉),则判断为该reference泄漏,进行下一步dump内存快照
//展示泄漏信息
if (!gone(reference)) {
long startDumpHeap = System.nanoTime();
long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
File heapDumpFile = heapDumper.dumpHeap();
if (heapDumpFile == RETRY_LATER) {
// Could not dump the heap.
return RETRY;
}
long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
heapdumpListener.analyze(
new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
gcDurationMs, heapDumpDurationMs));
}
return DONE;
}
总结一下
removeWeakReachableReferences()方法
private void removeWeaklyReachableReferences() {
// WeakReferences are enqueued as soon as the object to which they point to becomes weakly
// reachable. This is before finalization or garbage collection has actually happened.
KeyedWeakReference ref;
//若queue中存在该keyedWeakReference,则说明该keyedWeakReference对应的activity已被回收
while ((ref = (KeyedWeakReference) queue.poll()) != null) {
//从retainedKeys中移除,则retainedKeys剩下的就是泄漏的
retainedKeys.remove(ref.key);
}
}
其逻辑就是在queue里面的到key,然后从retainedKeys中移除。
gone()方法:
private boolean gone(KeyedWeakReference reference) {
return !retainedKeys.contains(reference.key);
}
就是一个contains判断
第三步:展示泄漏信息,也就是获取dumpheap以及对这个dumpheap进行analyze。
调用比较简单,而逻辑实现又是依托另外一个项目:HAHA。
heapdumpListener.analyze(
new HeapDump(heapDumpFile, reference.key,
reference.name, excludedRefs, watchDurationMs,
gcDurationMs, heapDumpDurationMs));
这里的heapdumpListener是第一步构建watcher时listenerServiceClass(DisplayLeakService.class)里面创建的
最后是ServiceHeapDumpListener这个类封装了analyze逻辑:
@Override public void analyze(HeapDump heapDump) {
checkNotNull(heapDump, "heapDump");
HeapAnalyzerService.runAnalysis(context, heapDump, listenerServiceClass);
}
runAnalysis()方法中就是启动一个服务处理heapDump
public static void runAnalysis(Context context, HeapDump heapDump,
Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
Intent intent = new Intent(context, HeapAnalyzerService.class);
intent.putExtra(LISTENER_CLASS_EXTRA, listenerServiceClass.getName());
intent.putExtra(HEAPDUMP_EXTRA, heapDump);
context.startService(intent);
}
HeapAnalyzerService.onHandIntent()中收到启动服务请求,调用checkForLeak
@Override
protected void onHandleIntent(Intent intent) {
if (intent == null) {
CanaryLog.d("HeapAnalyzerService received a null intent, ignoring.");
return;
}
String listenerClassName = intent.getStringExtra(LISTENER_CLASS_EXTRA);
HeapDump heapDump = (HeapDump) intent.getSerializableExtra(HEAPDUMP_EXTRA);
HeapAnalyzer heapAnalyzer = new HeapAnalyzer(heapDump.excludedRefs);
AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey);
AbstractAnalysisResultService.sendResultToListener(this, listenerClassName, heapDump, result);
}
checkForLeak()方法:
public AnalysisResult checkForLeak(File heapDumpFile, String referenceKey) {
long analysisStartNanoTime = System.nanoTime();
if (!heapDumpFile.exists()) {
Exception exception = new IllegalArgumentException("File does not exist: " + heapDumpFile);
return failure(exception, since(analysisStartNanoTime));
}
try {
HprofBuffer buffer = new MemoryMappedFileBuffer(heapDumpFile);
HprofParser parser = new HprofParser(buffer);
//将heapDumpFile转化为Snapshot
Snapshot snapshot = parser.parse();
deduplicateGcRoots(snapshot);
//找到泄漏对象引用
Instance leakingRef = findLeakingReference(referenceKey, snapshot);
// False alarm, weak reference was cleared in between key check and heap dump.
if (leakingRef == null) {
return noLeak(since(analysisStartNanoTime));
}
//返回泄漏对象的最短路径
return findLeakTrace(analysisStartNanoTime, snapshot, leakingRef);
} catch (Throwable e) {
return failure(e, since(analysisStartNanoTime));
}
}
主要有以下几个步骤:
其中第三步的findLeakingReference方法
private Instance findLeakingReference(String key, Snapshot snapshot) {
//找到快照中的KeyedWeakReference类对象
ClassObj refClass = snapshot.findClass(KeyedWeakReference.class.getName());
List<String> keysFound = new ArrayList<>();
//遍历这个类的所有实例
for (Instance instance : refClass.getInstancesList()) {
List<ClassInstance.FieldValue> values = classInstanceValues(instance);
//key值和最开始定义封装的key值相同,说明该实例是泄漏对象
String keyCandidate = asString(fieldValue(values, "key"));
if (keyCandidate.equals(key)) {
return fieldValue(values, "referent");
}
keysFound.add(keyCandidate);
}
throw new IllegalStateException(
"Could not find weak reference with key " + key + " in " + keysFound);
}