IT虾米网

LeakCanary原理分析详解

developer 2021年06月07日 手机开发 252 0

LeakCanary是一个检测内存泄漏的工具,使用非常简单。主要用来检测Activity和Fragment内存泄漏,如果发生内存泄漏,直接在用UI显示哪里发生了泄漏并展示对象引用链。

LeakCanary地址:IT虾米网

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)) {
    // 是否在主进程 
            refWatcher = LeakCanary.install(this); 
        } 
    } 
} 

如果想监视其他的Object是否内存泄漏了

refWatcher.watch(Object object) 

原理

在LeakCanary 的 wiki 就简述了基本的原理:

  1. RefWatcher.watch() 为监视的对象创建一个 KeyedWeakReference;
  2. 然后,后台线程会检查引用是否被清除回收了,如果没有就触发GC;
  3. 如果引用还没被清除,则堆内存dump到文件系统,成一个.hprof文件
  4. HeapAnalyzerService运行在另外一个进程,其中内部的HeapAnalyzer 使用HAHA库解析heap dump
  5. 根据reference key,HeapAnalyzer 找到对应的 KeyedWeakReference,定位内存泄露
  6. HeapAnalyzer 可以找出 GC roots 的最短强引用路径,并确定是否是泄露。如果泄漏,建立导致泄露的引用链。
  7. 将泄漏结果(引用链)传给App进程DisplayLeakService,通知展示

我们主要看的就是LeakCanary.install(this)到底发生了什么?

在解析流程之前先看下涉及到的几个重要的类:

在这里插入图片描述

  1. RefWatcher: 核心类,负责管理和提供入口watch(),由AndroidRefWatcherBuilder创建RefWatcher,建造者模式

  2. WatchExecutor: 负责控制执行检测内存泄漏任务

  3. DebuggerControl:判断是否处于debug

  4. GcTrigger:负责触发一次GC

  5. HeapDump:表示指定时刻的堆栈的快照,AndroidHeapDump为子类

  6. HeapDump.Builder: 负责创建HeapDump

  7. HeapDump.Listener:监听器,当发生内存泄漏的时候,会收到消息,需要触发分析AndroidHeapDump任务

  8. ServiceHeapDumpListener:HeapDump.Listener的实现类,当触发分析任务,调用HeapAnalyzerService执行分析任务

  9. HeapAnalyzerService:是一个Android中四大组件之一的Service,运行在独立的进程,负责执行分析任务和UI通知

  10. HeapAnalyzer:在HeapAnalyzerService内部中,是对DumpHeap分析内存泄漏和找出引用链的工具

  11. retainKeys: 是一个Set,保存着当前还没被回收的Reference的key

  12. ReferenceQueue:引用队列,WeakReference可以关联引用队列,当reference被回收时,会被加入到ReferenceQueue,这样我们就可以判断哪些对象没有被回收了

  13. DisplayLeakService:记录泄漏日志和展示通知的Service

其实,leakCanary的基本原理就是利用ReferenceQueue,在Activity销毁的时候判断对象有没有被加入ReferenceQueue,若没有则说明Activity还在存活,可能存在泄漏。

GC Root的种类

java 使用引用链法来判断一个引用是否该被回收,而出发点就是GC Root

  1. 虚拟机栈的对象引用
  2. 本地方法栈的对象引用
  3. 方法区的常量引用
  4. 方法区的静态对象引用

源码分析

isInAnalyzerProcess()方法是用来判断当前的进程是否是在分析进程,因为多进程中,每个进程都会创建Application,而我们需要在非LeakCanary的进程中检测。

// 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的总入口

public static @NonNull RefWatcher install(@NonNull Application application) {
    
  return refWatcher(application).listenerServiceClass(DisplayLeakService.class) 
      .excludedRefs(AndroidExcludedRefs.createAppDefaults().build()) 
      .buildAndInstall(); 
} 

这里使用了Build建造者模式,利用AndroidRefWatcherBuilder创建RefWatcher

我们分成几个部分:

  1. refWatch(application) 创建AndroidRefWatcherBuilder
  2. listenerServiceClass(DisplayLeakService.class) 设置监听内存泄漏和分析结果的 Service
  3. excludedRefs(AndroidExcludedRefs.createAppDefaults().build()) 设置忽略的内存泄漏的错误
  4. buildAndInstall() 初始化AndroidRefWatcher
1. refWatch(application)
// LeakCanary 
public static @NonNull AndroidRefWatcherBuilder refWatcher(@NonNull Context context) {
    
  return new AndroidRefWatcherBuilder(context); 
} 

这里只是创建了AndroidRefWatcherBuilder,最后使用Build模式创建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)); 
} 

创建了heapDumpListener负责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(),实际上也只是通知了HeapAnalyzerService.runAnalysis()去分析heapDump;

HeapAnalyzerService是运行在独立进程的Service。它是一个IntentService,执行完一次任务就会终止。

3. excludedRefs(AndroidExcludedRefs.createAppDefaults().build())

AndroidExcludedRefs.java类中维护着一系列的特定的内存泄漏类型,在执行内存泄漏和显示的时候也会忽略这些类

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

这里也主要分成四个部分:
(1). build() 构建初始化RefWatcher
(2). LeakCancaryInternals.setEnabledAsync(context, DisplayLeakActivity.class, true) 设置DisplayLeakActivity不显示图标
(3). ActivityRefWatcher.install(context, refWatcher) 监测Activity
(4). FragmentRefWatcher.Helper.install(context, refWatcher) 监测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()方法内部负责创建默认的组件。AndroidRefWatcherBuilder 重写了部分默认方法。

// AndroidRefWatcherBuilder 
@Override protected @NonNull HeapDumper defaultHeapDumper() {
    
  LeakDirectoryProvider leakDirectoryProvider = 
      LeakCanaryInternals.getLeakDirectoryProvider(context); 
  // 创建默认的 AndroidHeapDumper 
  return new AndroidHeapDumper(context, leakDirectoryProvider); 
} 
 
@Override protected @NonNull DebuggerControl defaultDebuggerControl() {
    
  // 创建默认的 AndroidDebuggerControl 
  return new AndroidDebuggerControl(); 
} 
 
@Override protected @NonNull HeapDump.Listener defaultHeapDumpListener() {
    
  // 创建默认的 ServiceHeapDumpListener 
  return new ServiceHeapDumpListener(context, DisplayLeakService.class); 
} 
 
@Override protected @NonNull WatchExecutor defaultWatchExecutor() {
    
  // 创建默认的 AndroidWatchExecutor 
  return new AndroidWatchExecutor(DEFAULT_WATCH_DELAY_MILLIS); 
} 
 
@Override protected @NonNull 
List<Class<? extends Reachability.Inspector>> defaultReachabilityInspectorClasses() {
    
  // 创建默认的 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内部的并发线程池 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; 
  // 设置是否隐藏应用图标 
  packageManager.setComponentEnabledSetting(component, newState, DONT_KILL_APP); 
} 

如果设置一个app的mainActivity为COMPONENT_ENABLED_STATE_DISABLED状态,则不会再launcher的程序图标中发现该app。

这里设置了DisplayLeakActivity在Launcher程序图标不出现

(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); 
  // 监听application里面的Activity的生命周期 
  application.registerActivityLifecycleCallbacks(activityRefWatcher.lifecycleCallbacks); 
} 
 
private final Application.ActivityLifecycleCallbacks lifecycleCallbacks = 
    new ActivityLifecycleCallbacksAdapter() {
    
      @Override public void onActivityDestroyed(Activity activity) {
    
        refWatcher.watch(activity); 
      } 
    }; 

这里才是LeakCanary监测Activity的核心,利用ActivityLifecycleCallbacks监听Activity的生命周期,在Activity销毁的时候,onActivityDestroyed调用refWatcher.watch()

refWatcher.watch()执行了实际的核心工作,暂时先跳过,后续再继续分析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,用来监测Fragment,其中SupportFragmentRefWatcher是在leakcanary-support-fragment包通过反射添加进来,需要在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); 
} 

监测Fragment和监测Activity基本是一样的,利用了FragmentLifecycleCallbacks监听Fragment的生命周期,在销毁状态onFragmentViewDestroyed和onFragmentDestroyed分别检测View和Fragment。

refWatcher.watch(Object)

无论是检测Activity还是Fragment,或者是其他类型,都是调用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()主要的工作:

  1. 为检测的Object创建一个key,并添加进retainedKeys表示Objectha还存活
  2. 为Object创建一个弱应用,关联queue为引用队列
  3. ensureGoneAsync()执行监测任务
// 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) {
    
    // 添加任务到主线程Looper,等待Looper空闲时候执行 
    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空闲的时候执行任务。

简单总结下AndroidWatcherExecutor,等待主线程空闲的时候,在子线程执行ensureGone()

// RefWatcher 
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
    
  long gcStartNanoTime = System.nanoTime(); 
  long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime); 
 
  // 1. 从retainedKeys移除掉已经被会回收的弱引用的key 
  removeWeaklyReachableReferences(); 
 
 // 2. 如果是debug模式,会继续重试 
  if (debuggerControl.isDebuggerAttached()) {
    
    // The debugger can create false leaks. 
    return RETRY; 
  } 
 
 // 3. 若当前引用不在retainedKeys,说明不存在内存泄漏 
  if (gone(reference)) {
    
    return DONE; 
  } 
 
 // 4. 触发一次gc 
  gcTrigger.runGc(); 
 
 // 5.再次从retainedKeys移除掉已经被会回收的弱引用的key 
removeWeaklyReachableReferences(); 
 
  if (!gone(reference)) {
    
   // 存在内存泄漏 
    long startDumpHeap = System.nanoTime(); 
    long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime); 
    
   // 6. 创建heapDump文件,还没写入 
    File heapDumpFile = heapDumper.dumpHeap(); 
    if (heapDumpFile == RETRY_LATER) {
    
      // Could not dump the heap. 
      return RETRY; 
    } 
    long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap); 
	// 7. 创建heapDump 
    HeapDump heapDump = heapDumpBuilder.heapDumpFile(heapDumpFile).referenceKey(reference.key) 
        .referenceName(reference.name) 
        .watchDurationMs(watchDurationMs) 
        .gcDurationMs(gcDurationMs) 
        .heapDumpDurationMs(heapDumpDurationMs) 
        .build(); 
	// 8.调用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); 
  } 
} 

上面的注释把流程基本阐述清楚了,基本逻辑是

  1. 利用引用队列移除掉已经回收的对象
  2. 可能因为回收不及时,所以再次gc
  3. 若对象还没被回收,则发生内存泄漏
  4. 创建HeapDump,后台service执行分析任务

最后看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 就是从最上面传递过来的DisplayLeakService.class,最后他负责记录日志和展示通知。

runAnalysis() 启动了HeapAnalyzerService,它是一个IntentService运行在独立进程,负责分析HeapDump和显示通知,既然是IntentService,直接看onHandleIntent(),内部又调用了onHandleIntentInForeground()

protected void onHandleIntentInForeground(@Nullable Intent intent) {
    
    String listenerClassName = intent.getStringExtra(LISTENER_CLASS_EXTRA); // DisplayLeakService.class 
    HeapDump heapDump = (HeapDump) intent.getSerializableExtra(HEAPDUMP_EXTRA); 
	// 创建HeapAnalyzer 
    HeapAnalyzer heapAnalyzer = 
        new HeapAnalyzer(heapDump.excludedRefs, this, heapDump.reachabilityInspectorClasses); 
	// HeapAnanlyzer工具分析 
    AnalysisResult result = heapAnalyzer.checkForLeak(heapDump.heapDumpFile, heapDump.referenceKey, 
        heapDump.computeRetainedHeapSize); 
    // 启动DisplayLeakService记录日志和展示通知 
    AbstractAnalysisResultService.sendResultToListener(this, listenerClassName, heapDump, result); 
  } 

HeapAnalyzer 可以找出 GC roots 的最短强引用路径,并确定是否是泄露。如果泄漏,建立导致泄露的引用链。

// 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); 
	//创建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); 
    // 找出内存泄漏对象 
    Instance leakingRef = findLeakingReference(referenceKey, snapshot); 
	 //检测是否存在泄漏的引用 
    if (leakingRef == null) {
    
      String className = leakingRef.getClassObj().getClassName(); 
      return noLeak(className, since(analysisStartNanoTime)); 
    } 
	 //根据leakingRef寻找引用路径 
    return findLeakTrace(analysisStartNanoTime, snapshot, leakingRef, computeRetainedSize); 
  } catch (Throwable e) {
    
    return failure(e, since(analysisStartNanoTime)); 
  } 
} 

再往下就是如何分析HeapDump,不是本文的重点。

总结:

在这里插入图片描述

  1. 无论你是监测Activity还是Fragment亦或是其他Object,最后都是RefWatcher.watch(object)
  2. RefWatcher添加监测的引用, 在主线程 idle 后进行一次强制 gc 后再判断该引用是否在引用队列中,否则就可能是内存泄漏
  3. RefWatcher 通过 HeapDumper 创建HeapDump 和 hprof 文件
  4. HeapAnalyzerService的HeapAnalyzer 分析内存泄漏和找出引用链,最后DisplayLeakService通知

发布评论
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

WindowManagerService Window View 关系(一)详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。