内存泄漏分析工具:LeakCanary的原理分析

LeakCanary是Square开源的,用于检测活动的内存泄漏。
众所周知LeakCanary的使用时在application中调用LeakCanary.install(this)即可。但是LeakCanary究竟是如何分析内存泄漏并且产生通知的呢?
从LeakCanary的入口开始分析:(不要扣代码,只需了解大致实现思路即可)

 public static RefWatcher install(Application application) {
        return ((AndroidRefWatcherBuilder)refWatcher(application).listenerServiceClass(DisplayLeakService.class).excludedRefs(AndroidExcludedRefs.createAppDefaults().build())).buildAndInstall();
    }
public RefWatcher buildAndInstall() {
        RefWatcher refWatcher = this.build();
        if(refWatcher != RefWatcher.DISABLED) {
            LeakCanary.enableDisplayLeakActivity(this.context);
            ActivityRefWatcher.installOnIcsPlus((Application)this.context, refWatcher);
        }

        return refWatcher;
    }

获取RefWatcher的实例,并调用ActivityRefWatcher的installOnIcsPlus方法。RefWatcher从名字看就是检测引用的。

public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {
        if(VERSION.SDK_INT >= 14) {
            ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
            activityRefWatcher.watchActivities();
        }
    }

从这里可以看出,LeakCanary的使用是有sdk版本要求的。调用ActivityRefWatcher 的watchActivities方法。

public void watchActivities() {
        this.stopWatchingActivities();
        this.application.registerActivityLifecycleCallbacks(this.lifecycleCallbacks);
    }

注册了application的生命周期的回调,用于监听activity的生命周期的回调。再看一下lifecycleCallbacks

private final ActivityLifecycleCallbacks lifecycleCallbacks = new ActivityLifecycleCallbacks() {
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        }

        public void onActivityStarted(Activity activity) {
        }

        public void onActivityResumed(Activity activity) {
        }

        public void onActivityPaused(Activity activity) {
        }

        public void onActivityStopped(Activity activity) {
        }

        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        }

        public void onActivityDestroyed(Activity activity) {
            ActivityRefWatcher.this.onActivityDestroyed(activity);
        }
    };
void onActivityDestroyed(Activity activity) {
        this.refWatcher.watch(activity);
    }

发现只对onDestroy进行了监听。

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);
        }
    }

在activity调用onDestroy的时候,将该activity的引用进行watch。 this.retainedKeys.add(key);retainedKeys是一个Set集合。在一个活动传给RefWatcher时会创建一个唯一的对应这个活动,该密钥存入一个集合retainedKeys中。也就是说,所有我们想要观测的activity对应的retainedKeys唯一键都会被放入集合中。(如果为null,表示回收了;如果不为null,表示该activity出现了内存泄漏)然后调用ensureGoneAsync。

 private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
        this.watchExecutor.execute(new Retryable() {
            public Result run() {
                return RefWatcher.this.ensureGone(reference, watchStartNanoTime);
            }
        });
    }
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);
                this.heapdumpListener.analyze(new HeapDump(heapDumpFile, reference.key, reference.name, this.excludedRefs, watchDurationMs, gcDurationMs, heapDumpDurationMs));
            }

            return Result.DONE;
        }
    }
private void removeWeaklyReachableReferences() {
        KeyedWeakReference ref;
        while((ref = (KeyedWeakReference)this.queue.poll()) != null) {
            this.retainedKeys.remove(ref.key);
        }
    }

在调用onDestroy时,会将activity放入ReferenceQueue中;经removeWeaklyReachableReferences方法会将gc后依旧不为null的引用从retainedKeys中remove掉(此时retainedKeys中全是经过gc后为null的)。最后将ReferenceQueue中的value值对应retainedKeys找出不为null的value,这些即为内存泄漏的引用。
利用HeapAnalyzer对dump的内存情况进行分析并进一步确认,若确定发生泄漏,则利用DisplayLeakService发送通知。

你可能感兴趣的:(内存泄漏分析工具:LeakCanary的原理分析)