内存泄露之LeakCanary原理简析

1 监听Activity,Fragment生命周期

在Android中,当一个Activity走完onDestroy生命周期后,说明该页面已经被销毁了,应该被系统GC回收。

通过Application.registerActivityLifecycleCallbacks()方法注册Activity生命周期的监听,每当一个Activity页面销毁时候,获取到这个Activity去检测这个Activity是否真的被系统GC。

2 监听是否GC回收

在一个Activity执行完onDestroy()之后,将它放入WeakReference中,然后将这个WeakReference类型的Activity对象与ReferenceQueque关联。

  1. 检测该Activity是否系统回收,从弱引用队列ReferenceQueque分析关联对象,如果找到对象,说明已回收,未发生内存泄露。移除相应key。
  2. 如果未被回收,在ReferenceQueque中找不到关联对象,此时手动进行gc。
  3. 再次判断ReferenceQueque能否找到关联对象,若找不到,则发生内存泄露
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;
    }
    if (gone(reference)) {
      return DONE;
    }
    gcTrigger.runGc();
    removeWeaklyReachableReferences();
    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;
}

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;
    while ((ref = (KeyedWeakReference) queue.poll()) != null) {
        retainedKeys.remove(ref.key);
    }
}

private boolean gone(KeyedWeakReference reference) {
    return !this.retainedKeys.contains(reference.key);
}

知识点1:gc之后,jvm会回收弱引用的对象,即回收WeakReference类型的Activity对象,防止内存泄露

知识点2:被回收的WeakReference类型的Activity对象,会被添加到ReferenceQueque中

知识点3:软引用的对象,调用gc,只有在内存不足时,jvm才会回收

3 分析泄露

最后用HAHA这个开源库去分析dump之后的heap内存。

原文地址:https://www.cnblogs.com/suiyilaile/p/15219181.html