美文网首页
内存泄漏分析工具:LeakCanary的原理分析

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

作者: jiting45 | 来源:发表于2017-11-14 19:11 被阅读0次

    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的原理分析

          本文链接:https://www.haomeiwen.com/subject/uulfvxtx.html