LeakCanary是一個(gè)檢測內(nèi)存泄漏的工具,使用非常簡單。主要用來檢測Activity和Fragment內(nèi)存泄漏,如果發(fā)生內(nèi)存泄漏链患,直接在用UI顯示哪里發(fā)生了泄漏并展示對象引用鏈吸占。
LeakCanary地址:https://github.com/square/leakcanary
LeakCanary的使用
在gradle文件中加入依賴
debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'
// 如果使用了 support fragment晴叨,需要依賴
debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3'
在Application中加入
public class MyApplication extends Application {
private RefWatcher refWatcher = null;
@Override
public void onCreate() {
super.onCreate();
if (!LeakCanary.isInAnalyzerProcess(this)) { // 是否在主進(jìn)程
refWatcher = LeakCanary.install(this);
}
}
}
如果想監(jiān)視其他的Object是否內(nèi)存泄漏了
refWatcher.watch(Object object)
原理
在LeakCanary 的 wiki 就簡述了基本的原理:
- RefWatcher.watch() 為監(jiān)視的對象創(chuàng)建一個(gè) KeyedWeakReference;
- 然后矾屯,后臺線程會檢查引用是否被清除回收了兼蕊,如果沒有就觸發(fā)GC;
- 如果引用還沒被清除件蚕,則堆內(nèi)存dump到文件系統(tǒng)孙技,成一個(gè).hprof文件
- HeapAnalyzerService運(yùn)行在另外一個(gè)進(jìn)程,其中內(nèi)部的HeapAnalyzer 使用HAHA庫解析heap dump
- 根據(jù)reference key骤坐,HeapAnalyzer 找到對應(yīng)的 KeyedWeakReference绪杏,定位內(nèi)存泄露
- HeapAnalyzer 可以找出 GC roots 的最短強(qiáng)引用路徑,并確定是否是泄露纽绍。如果泄漏蕾久,建立導(dǎo)致泄露的引用鏈。
- 將泄漏結(jié)果(引用鏈)傳給App進(jìn)程DisplayLeakService拌夏,通知展示
我們主要看的就是LeakCanary.install(this)
到底發(fā)生了什么僧著?
在解析流程之前先看下涉及到的幾個(gè)重要的類:
RefWatcher: 核心類,負(fù)責(zé)管理和提供入口watch()障簿,由AndroidRefWatcherBuilder創(chuàng)建RefWatcher盹愚,建造者模式
WatchExecutor: 負(fù)責(zé)控制執(zhí)行檢測內(nèi)存泄漏任務(wù)
DebuggerControl:判斷是否處于debug
GcTrigger:負(fù)責(zé)觸發(fā)一次GC
HeapDump:表示指定時(shí)刻的堆棧的快照,AndroidHeapDump為子類
HeapDump.Builder: 負(fù)責(zé)創(chuàng)建HeapDump
HeapDump.Listener:監(jiān)聽器站故,當(dāng)發(fā)生內(nèi)存泄漏的時(shí)候皆怕,會收到消息,需要觸發(fā)分析AndroidHeapDump任務(wù)
ServiceHeapDumpListener:HeapDump.Listener的實(shí)現(xiàn)類西篓,當(dāng)觸發(fā)分析任務(wù)愈腾,調(diào)用HeapAnalyzerService執(zhí)行分析任務(wù)
HeapAnalyzerService:是一個(gè)Android中四大組件之一的Service,運(yùn)行在獨(dú)立的進(jìn)程岂津,負(fù)責(zé)執(zhí)行分析任務(wù)和UI通知
HeapAnalyzer:在HeapAnalyzerService內(nèi)部中虱黄,是對DumpHeap分析內(nèi)存泄漏和找出引用鏈的工具
retainKeys: 是一個(gè)Set<String>,保存著當(dāng)前還沒被回收的Reference的key
ReferenceQueue:引用隊(duì)列吮成,WeakReference可以關(guān)聯(lián)引用隊(duì)列橱乱,當(dāng)reference被回收時(shí),會被加入到ReferenceQueue粱甫,這樣我們就可以判斷哪些對象沒有被回收了
DisplayLeakService:記錄泄漏日志和展示通知的Service
其實(shí)泳叠,leakCanary的基本原理就是利用ReferenceQueue,在Activity銷毀的時(shí)候判斷對象有沒有被加入ReferenceQueue茶宵,若沒有則說明Activity還在存活析二,可能存在泄漏。
GC Root的種類
java 使用引用鏈法來判斷一個(gè)引用是否該被回收,而出發(fā)點(diǎn)就是GC Root
- 虛擬機(jī)棧的對象引用
- 本地方法棧的對象引用
- 方法區(qū)的常量引用
- 方法區(qū)的靜態(tài)對象引用
源碼分析
isInAnalyzerProcess()
方法是用來判斷當(dāng)前的進(jìn)程是否是在分析進(jìn)程叶摄,因?yàn)槎噙M(jìn)程中,每個(gè)進(jìn)程都會創(chuàng)建Application安拟,而我們需要在非LeakCanary的進(jìn)程中檢測蛤吓。
// LeakCanary
public static boolean isInAnalyzerProcess(@NonNull Context context) {
Boolean isInAnalyzerProcess = LeakCanaryInternals.isInAnalyzerProcess;
// This only needs to be computed once per process.
if (isInAnalyzerProcess == null) {
isInAnalyzerProcess = isInServiceProcess(context, HeapAnalyzerService.class);
LeakCanaryInternals.isInAnalyzerProcess = isInAnalyzerProcess;
}
return isInAnalyzerProcess;
}
install方法是LeakCanary的總?cè)肟?/p>
public static @NonNull RefWatcher install(@NonNull Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
這里使用了Build建造者模式,利用AndroidRefWatcherBuilder創(chuàng)建RefWatcher
我們分成幾個(gè)部分:
- refWatch(application) 創(chuàng)建AndroidRefWatcherBuilder
- listenerServiceClass(DisplayLeakService.class) 設(shè)置監(jiān)聽內(nèi)存泄漏和分析結(jié)果的 Service
- excludedRefs(AndroidExcludedRefs.createAppDefaults().build()) 設(shè)置忽略的內(nèi)存泄漏的錯(cuò)誤
- buildAndInstall() 初始化AndroidRefWatcher
1. refWatch(application)
// LeakCanary
public static @NonNull AndroidRefWatcherBuilder refWatcher(@NonNull Context context) {
return new AndroidRefWatcherBuilder(context);
}
這里只是創(chuàng)建了AndroidRefWatcherBuilder糠赦,最后使用Build模式創(chuàng)建AndroidRefWatcher
2.listenerServiceClass(DisplayLeakService.class)
// AndroidRefWatcherBuilder
public @NonNull AndroidRefWatcherBuilder listenerServiceClass(
@NonNull Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
enableDisplayLeakActivity = DisplayLeakService.class.isAssignableFrom(listenerServiceClass);
return heapDumpListener(new ServiceHeapDumpListener(context, listenerServiceClass));
}
創(chuàng)建了heapDumpListener負(fù)責(zé)heapDump的分析和處理
isAssignableFrom() 是object方法会傲,
例如 a.isAssignableFrom(b) 判斷a是不是b的父類或接口
如果listenerServiceClass繼承或者是DisplayLeakService,則enableDisplayLeakActiviy為true拙泽,表示顯示LeakCanary界面
// ServiceHeapDumpListener
public final class ServiceHeapDumpListener implements HeapDump.Listener {
private final Context context;
private final Class<? extends AbstractAnalysisResultService> listenerServiceClass;
public ServiceHeapDumpListener(@NonNull final Context context,
@NonNull final Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
this.listenerServiceClass = checkNotNull(listenerServiceClass, "listenerServiceClass");
this.context = checkNotNull(context, "context").getApplicationContext();
}
@Override public void analyze(@NonNull HeapDump heapDump) {
checkNotNull(heapDump, "heapDump");
HeapAnalyzerService.runAnalysis(context, heapDump, listenerServiceClass);
}
}
這里簡單看一下ServiceHeapDumpListener 淌山,主要方法在analyze()
,實(shí)際上也只是通知了HeapAnalyzerService.runAnalysis()去分析heapDump顾瞻;
HeapAnalyzerService是運(yùn)行在獨(dú)立進(jìn)程的Service泼疑。它是一個(gè)IntentService,執(zhí)行完一次任務(wù)就會終止荷荤。
3. excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
AndroidExcludedRefs.java類中維護(hù)著一系列的特定的內(nèi)存泄漏類型退渗,在執(zhí)行內(nèi)存泄漏和顯示的時(shí)候也會忽略這些類
4. buildAndInstall()
// AndroidRefWatcherBuilder
public @NonNull RefWatcher buildAndInstall() {
if (LeakCanaryInternals.installedRefWatcher != null) {
throw new UnsupportedOperationException("buildAndInstall() should only be called once.");
}
RefWatcher refWatcher = build();
if (refWatcher != DISABLED) {
if (enableDisplayLeakActivity) {
LeakCanaryInternals.setEnabledAsync(context, DisplayLeakActivity.class, true);
}
if (watchActivities) {
ActivityRefWatcher.install(context, refWatcher);
}
if (watchFragments) {
FragmentRefWatcher.Helper.install(context, refWatcher);
}
}
LeakCanaryInternals.installedRefWatcher = refWatcher;
return refWatcher;
}
這里也主要分成四個(gè)部分:
(1). build() 構(gòu)建初始化RefWatcher
(2). LeakCancaryInternals.setEnabledAsync(context, DisplayLeakActivity.class, true) 設(shè)置DisplayLeakActivity不顯示圖標(biāo)
(3). ActivityRefWatcher.install(context, refWatcher) 監(jiān)測Activity
(4). FragmentRefWatcher.Helper.install(context, refWatcher) 監(jiān)測Fragment
(1) build()
// RefWatcherBuilder
public final RefWatcher build() {
if (isDisabled()) {
return RefWatcher.DISABLED;
}
...
return new RefWatcher(watchExecutor, debuggerControl, gcTrigger, heapDumper, heapDumpListener,
heapDumpBuilder);
}
AndroidRefWatcherBuilder 是 RefWatcherBuilder的子類,build()方法內(nèi)部負(fù)責(zé)創(chuàng)建默認(rèn)的組件蕴纳。AndroidRefWatcherBuilder 重寫了部分默認(rèn)方法会油。
// AndroidRefWatcherBuilder
@Override protected @NonNull HeapDumper defaultHeapDumper() {
LeakDirectoryProvider leakDirectoryProvider =
LeakCanaryInternals.getLeakDirectoryProvider(context);
// 創(chuàng)建默認(rèn)的 AndroidHeapDumper
return new AndroidHeapDumper(context, leakDirectoryProvider);
}
@Override protected @NonNull DebuggerControl defaultDebuggerControl() {
// 創(chuàng)建默認(rèn)的 AndroidDebuggerControl
return new AndroidDebuggerControl();
}
@Override protected @NonNull HeapDump.Listener defaultHeapDumpListener() {
// 創(chuàng)建默認(rèn)的 ServiceHeapDumpListener
return new ServiceHeapDumpListener(context, DisplayLeakService.class);
}
@Override protected @NonNull WatchExecutor defaultWatchExecutor() {
// 創(chuàng)建默認(rèn)的 AndroidWatchExecutor
return new AndroidWatchExecutor(DEFAULT_WATCH_DELAY_MILLIS);
}
@Override protected @NonNull
List<Class<? extends Reachability.Inspector>> defaultReachabilityInspectorClasses() {
// 創(chuàng)建默認(rèn)的 AndroidReachabilityInspectors
return AndroidReachabilityInspectors.defaultAndroidInspectors();
}
(2) LeakCancaryInternals.setEnabledAsync(context, DisplayLeakActivity.class, true)
// LeakCanaryInternals
public static void setEnabledAsync(Context context, final Class<?> componentClass,
final boolean enabled) {
final Context appContext = context.getApplicationContext();
AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
@Override public void run() {
setEnabledBlocking(appContext, componentClass, enabled);
}
});
}
這里使用了AsyncTask內(nèi)部的并發(fā)線程池 setEnabledBlocking()
// LeakCanaryInternals
public static void setEnabledBlocking(Context appContext, Class<?> componentClass, boolean enabled) {
ComponentName component = new ComponentName(appContext, componentClass);
PackageManager packageManager = appContext.getPackageManager();
int newState = enabled ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DISABLED;
// 設(shè)置是否隱藏應(yīng)用圖標(biāo)
packageManager.setComponentEnabledSetting(component, newState, DONT_KILL_APP);
}
如果設(shè)置一個(gè)app的mainActivity為COMPONENT_ENABLED_STATE_DISABLED狀態(tài),則不會再launcher的程序圖標(biāo)中發(fā)現(xiàn)該app古毛。
這里設(shè)置了DisplayLeakActivity在Launcher程序圖標(biāo)不出現(xiàn)
(3). ActivityRefWatcher.install(context, refWatcher)
// ActivityRefWatcher
public static void install(@NonNull Context context, @NonNull RefWatcher refWatcher) {
Application application = (Application) context.getApplicationContext();
ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
// 監(jiān)聽application里面的Activity的生命周期
application.registerActivityLifecycleCallbacks(activityRefWatcher.lifecycleCallbacks);
}
private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
new ActivityLifecycleCallbacksAdapter() {
@Override public void onActivityDestroyed(Activity activity) {
refWatcher.watch(activity);
}
};
這里才是LeakCanary監(jiān)測Activity的核心翻翩,利用ActivityLifecycleCallbacks監(jiān)聽Activity的生命周期,在Activity銷毀的時(shí)候稻薇,onActivityDestroyed調(diào)用refWatcher.watch()
refWatcher.watch()執(zhí)行了實(shí)際的核心工作嫂冻,暫時(shí)先跳過,后續(xù)再繼續(xù)分析refWatcher.watch()
(4). FragmentRefWatcher.Helper.install(context, refWatcher)
// FragmentRefWatcher
final class Helper {
private static final String SUPPORT_FRAGMENT_REF_WATCHER_CLASS_NAME =
"com.squareup.leakcanary.internal.SupportFragmentRefWatcher";
public static void install(Context context, RefWatcher refWatcher) {
List<FragmentRefWatcher> fragmentRefWatchers = new ArrayList<>();
if (SDK_INT >= O) { // 如果大于Anroid 26颖低,需要增加AndroidOFragmentRefWatcher
fragmentRefWatchers.add(new AndroidOFragmentRefWatcher(refWatcher));
}
try {
// 利用反射添加SupportFragmentRefWatcher
Class<?> fragmentRefWatcherClass = Class.forName(SUPPORT_FRAGMENT_REF_WATCHER_CLASS_NAME);
Constructor<?> constructor =
fragmentRefWatcherClass.getDeclaredConstructor(RefWatcher.class);
FragmentRefWatcher supportFragmentRefWatcher =
(FragmentRefWatcher) constructor.newInstance(refWatcher);
fragmentRefWatchers.add(supportFragmentRefWatcher);
} catch (Exception ignored) {
}
if (fragmentRefWatchers.size() == 0) {
return;
}
Helper helper = new Helper(fragmentRefWatchers);
Application application = (Application) context.getApplicationContext();
application.registerActivityLifecycleCallbacks(helper.activityLifecycleCallbacks);
}
以上部分是添加了FragmentRefWatcher絮吵,用來監(jiān)測Fragment,其中SupportFragmentRefWatcher是在leakcanary-support-fragment包通過反射添加進(jìn)來忱屑,需要在build.gradle添加依賴蹬敲。
// AndroidOFragmentRefWatcher
private final FragmentManager.FragmentLifecycleCallbacks fragmentLifecycleCallbacks =
new FragmentManager.FragmentLifecycleCallbacks() {
@Override public void onFragmentViewDestroyed(FragmentManager fm, Fragment fragment) {
View view = fragment.getView();
if (view != null) {
refWatcher.watch(view);
}
}
@Override
public void onFragmentDestroyed(FragmentManager fm, Fragment fragment) {
refWatcher.watch(fragment);
}
};
@Override public void watchFragments(Activity activity) {
FragmentManager fragmentManager = activity.getFragmentManager();
fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true);
}
監(jiān)測Fragment和監(jiān)測Activity基本是一樣的,利用了FragmentLifecycleCallbacks監(jiān)聽Fragment的生命周期莺戒,在銷毀狀態(tài)onFragmentViewDestroyed和onFragmentDestroyed分別檢測View和Fragment伴嗡。
refWatcher.watch(Object)
無論是檢測Activity還是Fragment,或者是其他類型从铲,都是調(diào)用refWatcher.watch(Object)
再看下AnroidRefWatcher重要的組成部分:
public void watch(Object watchedReference) {
watch(watchedReference, "");
}
public void watch(Object watchedReference, String referenceName) {
if (this == DISABLED) {
return;
}
checkNotNull(watchedReference, "watchedReference");
checkNotNull(referenceName, "referenceName");
final long watchStartNanoTime = System.nanoTime();
String key = UUID.randomUUID().toString();
retainedKeys.add(key);//1
final KeyedWeakReference reference =
new KeyedWeakReference(watchedReference, key, referenceName, queue);//2
ensureGoneAsync(watchStartNanoTime, reference);//3
}
watch()主要的工作:
- 為檢測的Object創(chuàng)建一個(gè)key瘪校,并添加進(jìn)retainedKeys表示Objectha還存活
- 為Object創(chuàng)建一個(gè)弱應(yīng)用,關(guān)聯(lián)queue為引用隊(duì)列
- ensureGoneAsync()執(zhí)行監(jiān)測任務(wù)
// RefWatcher
private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
watchExecutor.execute(new Retryable() {
@Override public Retryable.Result run() {
return ensureGone(reference, watchStartNanoTime);
}
});
}
watchExecutor 是AndroidWatchExecutor
//AndroidWatchExecutor
public void execute(@NonNull Retryable retryable) {
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
// 在主線程
waitForIdle(retryable, 0);
} else {
// 切換到主線程
postWaitForIdle(retryable, 0);
}
}
private void postWaitForIdle(final Retryable retryable, final int failedAttempts) {
// 利用Handler切換到主線程
mainHandler.post(new Runnable() {
@Override public void run() {
waitForIdle(retryable, failedAttempts);
}
});
}
private void waitForIdle(final Retryable retryable, final int failedAttempts) {
// 添加任務(wù)到主線程Looper,等待Looper空閑時(shí)候執(zhí)行
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override public boolean queueIdle() {
postToBackgroundWithDelay(retryable, failedAttempts);
return false;
}
});
}
private void postToBackgroundWithDelay(final Retryable retryable, final int failedAttempts) {
long exponentialBackoffFactor = (long) Math.min(Math.pow(2, failedAttempts), maxBackoffFactor);
long delayMillis = initialDelayMillis * exponentialBackoffFactor;
// backgroudhandler所在的是HandlerThread
backgroundHandler.postDelayed(new Runnable() {
@Override public void run() {
Retryable.Result result = retryable.run();
if (result == RETRY) {
postWaitForIdle(retryable, failedAttempts + 1);
}
}
}, delayMillis);
}
這里利用Looper的IdleHandler阱扬,在Looper空閑的時(shí)候執(zhí)行任務(wù)泣懊。
簡單總結(jié)下AndroidWatcherExecutor,等待主線程空閑的時(shí)候麻惶,在子線程執(zhí)行ensureGone()
// RefWatcher
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
long gcStartNanoTime = System.nanoTime();
long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
// 1. 從retainedKeys移除掉已經(jīng)被會回收的弱引用的key
removeWeaklyReachableReferences();
// 2. 如果是debug模式馍刮,會繼續(xù)重試
if (debuggerControl.isDebuggerAttached()) {
// The debugger can create false leaks.
return RETRY;
}
// 3. 若當(dāng)前引用不在retainedKeys,說明不存在內(nèi)存泄漏
if (gone(reference)) {
return DONE;
}
// 4. 觸發(fā)一次gc
gcTrigger.runGc();
// 5.再次從retainedKeys移除掉已經(jīng)被會回收的弱引用的key
removeWeaklyReachableReferences();
if (!gone(reference)) {
// 存在內(nèi)存泄漏
long startDumpHeap = System.nanoTime();
long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
// 6. 創(chuàng)建heapDump文件窃蹋,還沒寫入
File heapDumpFile = heapDumper.dumpHeap();
if (heapDumpFile == RETRY_LATER) {
// Could not dump the heap.
return RETRY;
}
long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
// 7. 創(chuàng)建heapDump
HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key)
.referenceName(reference.name)
.watchDurationMs(watchDurationMs)
.gcDurationMs(gcDurationMs)
.heapDumpDurationMs(heapDumpDurationMs)
.build();
// 8.調(diào)用heapdumpListener分析
heapdumpListener.analyze(heapDump);
}
return DONE;
}
private boolean gone(KeyedWeakReference reference) {
return !retainedKeys.contains(reference.key);
}
private void removeWeaklyReachableReferences() {
KeyedWeakReference ref;
while ((ref = (KeyedWeakReference) queue.poll()) != null) {
retainedKeys.remove(ref.key);
}
}
上面的注釋把流程基本闡述清楚了卡啰,基本邏輯是
- 利用引用隊(duì)列移除掉已經(jīng)回收的對象
- 可能因?yàn)榛厥詹患皶r(shí),所以再次gc
- 若對象還沒被回收警没,則發(fā)生內(nèi)存泄漏
- 創(chuàng)建HeapDump匈辱,后臺service執(zhí)行分析任務(wù)
最后看HeapAnalyzerService分析HeapDump
// HeapAnalyzerService
public static void runAnalysis(Context context, HeapDump heapDump,
Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
setEnabledBlocking(context, HeapAnalyzerService.class, true);
setEnabledBlocking(context, listenerServiceClass, true);
Intent intent = new Intent(context, HeapAnalyzerService.class);
intent.putExtra(LISTENER_CLASS_EXTRA, listenerServiceClass.getName());
intent.putExtra(HEAPDUMP_EXTRA, heapDump);
ContextCompat.startForegroundService(context, intent);
}
這里的listenerServiceClass 就是從最上面?zhèn)鬟f過來的DisplayLeakService.class,最后他負(fù)責(zé)記錄日志和展示通知杀迹。
runAnalysis()
啟動(dòng)了HeapAnalyzerService亡脸,它是一個(gè)IntentService運(yùn)行在獨(dú)立進(jìn)程,負(fù)責(zé)分析HeapDump和顯示通知佛南,既然是IntentService梗掰,直接看onHandleIntent(),內(nèi)部又調(diào)用了onHandleIntentInForeground()
protected void onHandleIntentInForeground(@Nullable Intent intent) {
String listenerClassName = intent.getStringExtra(LISTENER_CLASS_EXTRA); // DisplayLeakService.class
HeapDump heapDump = (HeapDump) intent.getSerializableExtra(HEAPDUMP_EXTRA);
// 創(chuàng)建HeapAnalyzer
HeapAnalyzer heapAnalyzer =
new HeapAnalyzer(heapDump.excludedRefs, this, heapDump.reachabilityInspectorClasses);
// HeapAnanlyzer工具分析
AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey,
heapDump.computeRetainedHeapSize);
// 啟動(dòng)DisplayLeakService記錄日志和展示通知
AbstractAnalysisResultService.sendResultToListener(this, listenerClassName, heapDump, result);
}
HeapAnalyzer 可以找出 GC roots 的最短強(qiáng)引用路徑嗅回,并確定是否是泄露及穗。如果泄漏,建立導(dǎo)致泄露的引用鏈绵载。
// HeapAnalyzer
public @NonNull AnalysisResult checkForLeak(@NonNull File heapDumpFile,
@NonNull String referenceKey,
boolean computeRetainedSize) {
long analysisStartNanoTime = System.nanoTime();
if (!heapDumpFile.exists()) {
Exception exception = new IllegalArgumentException("File does not exist: " + heapDumpFile);
return failure(exception, since(analysisStartNanoTime));
}
try {
listener.onProgressUpdate(READING_HEAP_DUMP_FILE);
//將heap文件封裝成MemoryMappedFileBuffer
HprofBuffer buffer = new MemoryMappedFileBuffer(heapDumpFile);
//創(chuàng)建hprof解析器埂陆,解析hprof文件
HprofParser parser = new HprofParser(buffer);
listener.onProgressUpdate(PARSING_HEAP_DUMP);
Snapshot snapshot = parser.parse();
listener.onProgressUpdate(DEDUPLICATING_GC_ROOTS);
// 移除相同GC root
deduplicateGcRoots(snapshot);
listener.onProgressUpdate(FINDING_LEAKING_REF);
// 找出內(nèi)存泄漏對象
Instance leakingRef = findLeakingReference(referenceKey, snapshot);
//檢測是否存在泄漏的引用
if (leakingRef == null) {
String className = leakingRef.getClassObj().getClassName();
return noLeak(className, since(analysisStartNanoTime));
}
//根據(jù)leakingRef尋找引用路徑
return findLeakTrace(analysisStartNanoTime, snapshot, leakingRef, computeRetainedSize);
} catch (Throwable e) {
return failure(e, since(analysisStartNanoTime));
}
}
再往下就是如何分析HeapDump,不是本文的重點(diǎn)娃豹。
總結(jié):
- 無論你是監(jiān)測Activity還是Fragment亦或是其他Object焚虱,最后都是RefWatcher.watch(object)
- RefWatcher添加監(jiān)測的引用, 在主線程 idle 后進(jìn)行一次強(qiáng)制 gc 后再判斷該引用是否在引用隊(duì)列中懂版,否則就可能是內(nèi)存泄漏
- RefWatcher 通過 HeapDumper 創(chuàng)建HeapDump 和 hprof 文件
- HeapAnalyzerService的HeapAnalyzer 分析內(nèi)存泄漏和找出引用鏈鹃栽,最后DisplayLeakService通知