阿里一面之LeakCanary内存泄漏监测原理总结
本文通过在阿里面试遇到的问题总结而出,如有不对地方,请及时批评指正。篇幅较长,请耐心阅读。简介:
LeakCanary是一个开源的内存泄漏检查工具,使用简单,主要用来监测Activity和Fragment是否发生内存泄漏。如果发生内存泄漏,直接以引用链的形式展示出造成内存泄漏对象。使用步骤添加build。gradle依懒。debugImplementationcom。squareup。leakcanary:leakcanaryandroid:1。6。3releaseImplementationcom。squareup。leakcanary:leakcanaryandroidnoop:1。6。3debugImplementationcom。squareup。leakcanary:leakcanarysupportfragment:1。6。3
2。在Application中初始化LeakCanary。classCustomApplication:MainApplication(){overridefunonCreate(){super。onCreate()if(!LeakCanary。isInAnalyzerProcess(this)){LeakCanary。install(this);}}}
完成以上两步操作之后,当打开app运行时,如果Activity或Fragment发生内存泄漏,会以通知的形式提醒用户。源码分析
先通过流程图来看一下LeakCanary工作原理,如图所示:
LeakCanary初始化
1。在application中注册。classCustomApplication:MainApplication(){overridefunonCreate(){super。onCreate()if(!LeakCanary。isInAnalyzerProcess(this)){注册leakcanaryLeakCanary。install(this);}}}
2。构建观察者RefWatcher。publicstaticRefWatcherinstall(Applicationapplication){构建观察者RefWatcherreturnrefWatcher(application)。listenerServiceClass(DisplayLeakService。class)。excludedRefs(AndroidExcludedRefs。createAppDefaults()。build())。buildAndInstall();}
3。构建不同的观察者ActivityRefWatcher或FragmentRefWatcher。publicRefWatcherbuildAndInstall(){if(LeakCanaryInternals。installedRefWatcher!null){thrownewUnsupportedOperationException(buildAndInstall()shouldonlybecalledonce。);}RefWatcherrefWatcherbuild();if(refWatcher!DISABLED){观察activityif(watchActivities){ActivityRefWatcher。install(context,refWatcher);}观察fragmentif(watchFragments){FragmentRefWatcher。Helper。install(context,refWatcher);}}LeakCanaryInternals。installedRefWatcherrefWatcher;returnrefWatcher;}
4。监测activity生命周期。publicstaticvoidinstall(Contextcontext,RefWatcherrefWatcher){Applicationapplication(Application)context。getApplicationContext();ActivityRefWatcheractivityRefWatchernewActivityRefWatcher(application,refWatcher);注册生命周期application。registerActivityLifecycleCallbacks(activityRefWatcher。lifecycleCallbacks);}
5。将观察对象activity添加到被观察者队列。privatefinalApplication。ActivityLifecycleCallbackslifecycleCallbacksnewActivityLifecycleCallbacksAdapter(){OverridepublicvoidonActivityDestroyed(Activityactivity){在activity的onDestroy生命周期中添加观察对象refWatcher。watch(activity);}};泄漏检测
1。将被观察对象包装成弱引用。publicvoidwatch(ObjectwatchedReference,StringreferenceName){if(thisDISABLED){return;}判空检查checkNotNull(watchedReference,watchedReference);checkNotNull(referenceName,referenceName);finallongwatchStartNanoTimeSystem。nanoTime();生成唯一keyStringkeyUUID。randomUUID()。toString();保存keyretainedKeys。add(key);包装成弱引用对象finalKeyedWeakReferencereferencenewKeyedWeakReference(watchedReference,key,referenceName,queue);检查被观察对象是否被回收ensureGoneAsync(watchStartNanoTime,reference);}
2。检测弱引用对象是否被回收。SuppressWarnings(ReferenceEquality)Explicitlycheckingfornamednull。Retryable。ResultensureGone(finalKeyedWeakReferencereference,finallongwatchStartNanoTime){longgcStartNanoTimeSystem。nanoTime();longwatchDurationMsNANOSECONDS。toMillis(gcStartNanoTimewatchStartNanoTime);移除被回收对象的keyremoveWeaklyReachableReferences();if(debuggerControl。isDebuggerAttached()){Thedebuggercancreatefalseleaks。returnRETRY;}判断弱引用是否被回收if(gone(reference)){returnDONE;}触发系统GC进行垃圾回收gcTrigger。runGc();再次移除被回收对象的keyremoveWeaklyReachableReferences();判断弱引用对象是否被回收if(!gone(reference)){将没有被回收对象的内存快照保存成文件longstartDumpHeapSystem。nanoTime();longgcDurationMsNANOSECONDS。toMillis(startDumpHeapgcStartNanoTime);FileheapDumpFileheapDumper。dumpHeap();if(heapDumpFileRETRYLATER){Couldnotdumptheheap。returnRETRY;}longheapDumpDurationMsNANOSECONDS。toMillis(System。nanoTime()startDumpHeap);构建内存快照文件HeapDumpheapDumpheapDumpBuilder。heapDumpFile(heapDumpFile)。referenceKey(reference。key)。referenceName(reference。name)。watchDurationMs(watchDurationMs)。gcDurationMs(gcDurationMs)。heapDumpDurationMs(heapDumpDurationMs)。build();将内存信息回调出去heapdumpListener。analyze(heapDump);}returnDONE;}内存分析
1。启动HeapAnalyzerService进行内存分析Overridepublicvoidanalyze(HeapDumpheapDump){checkNotNull(heapDump,heapDump);HeapAnalyzerService。runAnalysis(context,heapDump,listenerServiceClass);}
2。保存文件,并发送通知给用户OverrideprotectedfinalvoidonHeapAnalyzed(HeapDumpheapDump,AnalysisResultresult){StringleakInfoleakInfo(this,heapDump,result,true);CanaryLog。d(s,leakInfo);booleanresultSavedfalse;booleanshouldSaveResultresult。leakFoundresult。failure!null;if(shouldSaveResult){保存内存文件heapDumprenameHeapdump(heapDump);resultSavedsaveResult(heapDump,result);}PendingIntentpendingIntent;StringcontentTitle;StringcontentText;解析内存文件if(!shouldSaveResult){contentTitlegetString(R。string。leakcanarynoleaktitle);contentTextgetString(R。string。leakcanarynoleaktext);pendingIntentnull;}elseif(resultSaved){pendingIntentDisplayLeakActivity。createPendingIntent(this,heapDump。referenceKey);if(result。failurenull){if(result。retainedHeapSizeAnalysisResult。RETAINEDHEAPSKIPPED){StringclassNameclassSimpleName(result。className);if(result。excludedLeak){contentTitlegetString(R。string。leakcanaryleakexcluded,className);}else{contentTitlegetString(R。string。leakcanaryclasshasleaked,className);}}else{StringsizeformatShortFileSize(this,result。retainedHeapSize);StringclassNameclassSimpleName(result。className);if(result。excludedLeak){contentTitlegetString(R。string。leakcanaryleakexcludedretaining,className,size);}else{contentTitlegetString(R。string。leakcanaryclasshasleakedretaining,className,size);}}}else{contentTitlegetString(R。string。leakcanaryanalysisfailed);}contentTextgetString(R。string。leakcanarynotificationmessage);}else{contentTitlegetString(R。string。leakcanarycouldnotsavetitle);contentTextgetString(R。string。leakcanarycouldnotsavetext);pendingIntentnull;}每次发送一个新通知提醒用户。intnotificationId(int)(SystemClock。uptimeMillis()1000);showNotification(this,contentTitle,contentText,pendingIntent,notificationId);afterDefaultHandling(heapDump,result,leakInfo);}
整个监测过程主要作用如下:
1。注册监听activity生命周期。
2。在activity被销毁时加入弱引用队列。
3。第一次移除不可达对象,移除ReferenceQueue中的KeyedWeakReference。
4。主动触发GC进行垃圾回收。
5。第二次移除不可达对象,移除ReferenceQueue中的KeyedWeakReference。
6。判断当前是否还有对象存活,如果有保存存活对象的内存快照heapDumpFile,然后进行内存分析。
7。启动HeapAnalyzerService对内存快照进行分析,找出GCroots引用链。
8。发送通知给用户。
以上就是阿里面试后总结的几个要点,还不会的同学赶紧学起来吧,感谢您的阅读,创造不易,如果您觉得本篇文章对您有帮助,请点击关注小编,您的支持就是小编创作的最大动力!