LeakCanary的Activity的监听泄漏流程:
LeakCanary.installl()—〉
AndroidRefWatcherBuilder.buildAndInstall()—〉
RefWatcher创建—〉
ActivityRefWatcher.install(context, refWatcher)—〉
ActivityRefWatcher.install#registerActivityLifecycleCallbacks—〉lifecycleCallbacks.onActivityDestroyed#refWatcher.watch(activity)—〉
RefWatcher.watch()(activity指向的weakReference放入ReferenceQueue,Set放入随机key)—〉
RefWatcher.ensureGoneAsync()—〉
RefWatcher.removeWeaklyReachableReferences()—>
ReferenceQueue queue引用队列轮询检查Activity的弱引用(一些等待逻辑)—〉
runGc—〉
再次执行ReferenceQueue检查—〉
queue.poll()一直是null,Set无法remove掉对应key(即activity指向的weakReference没有释放就是内存泄漏)。
下面附加一个熟悉引用优化和引用队列的例子(摘自“姜新星”老师的GC 回收机制与分代回收策略的文章例子):
public class SoftReferenceTest {
public static class MyBigObject {
byte[] data = new byte[1024];//1KB
}
public static int removedSoftRefs = 0;
public static int CACHE_INITIAL_CAPACITY = 100 * 1024;//100M
public static Set<SoftReference<MyBigObject>> cache = new HashSet<>(CACHE_INITIAL_CAPACITY);
public static ReferenceQueue<MyBigObject> referenceQueue = new ReferenceQueue<>();
public static void main(String[] args) {
for (int i = 0; i < CACHE_INITIAL_CAPACITY; i++) {
MyBigObject obj = new MyBigObject();
cache.add(new SoftReference<>(obj, referenceQueue));
clearUselessReferences();
if (i % 10000 == 0) {
System.out.println("size of cache : " + cache.size());
}
}
System.out.println("End,removed soft reference = " + removedSoftRefs);
}
public static void clearUselessReferences() {
Reference<? extends MyBigObject> ref = referenceQueue.poll();
while (ref != null) {
if (cache.remove(ref)) {
removedSoftRefs++;
}
ref = referenceQueue.poll();
}
}
}
注:运行例子时可以设置VM option为-Xms4M -Xmx4M -Xmn2M。
只有了解源码,并从源码的角度分析,才会找到更完美的解决方案。悟已往之不谏,知来者之可追。实迷途其未远,觉今是而昨非。纸上得来终觉浅,绝知此事要躬行,加油!