LeakCanary2源码分析

本文详细介绍了LeakCanary2在Android上的应用,包括其内存泄漏检测的原理,从添加依赖、简单实践到源码分析。重点讲解了ActivityDestroyWatcher和FragmentDestroyWatcher的安装过程,以及HeapAnalyzerService如何进行内存分析。通过对源码的深入理解,展示了LeakCanary2如何帮助开发者发现并解决内存泄漏问题。


LeakCanary介绍

A memory leak detection library for Android.

LeakCanary是Android上用于检查内存泄漏的工具,LeakCanary大大减少因内存泄漏导致的内存溢出(OutOfMemoryError)奔溃,LeakCanary的易用和有效让它成为我最喜欢的开源框架之一,下面我们会先简单介绍其用法,然后深入了解LeakCanary检查内存泄漏的原理。

LeakCanary使用
加入依赖
dependencies {
  // debugImplementation because LeakCanary should only run in debug builds.
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.2'
}

只需要添加相关依赖,便可集成,非常方便,如果从1.6版本升级,可以参考《Upgrading to LeakCanary 2》进行升级。

安装并启动APP,看到下面这个log,说明已经添加成功:

D/LeakCanary: Installing AppWatcher
简单实践
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.d("MainActivity","Run");
            }
        }, 10000);
    }
}

这里我们写了个10s的延时任务,打开APP后迅速按返回键退出,这个时候LeakCanary有如下提示:

检查结果UI显示

LeakCanary的提示我们可以知道,MainActivity发生了内存泄漏,而泄漏的原因是MessageQueue持有了MainActivity,导致MainActivity无法正常退出,这里只是简单举例,大家可以加到自己项目中,相信会有不少收获。

LeakCanary源码分析

本文使用的是LeakCanary最新的2.2版本

从1.6.3开始,LeakCanary就使用Kotlin重写了一次,代码量(不包括空格和注释)从Java时期的6000增加到Kotlin版本的16000行,代码增加的原因是LeakCanary不在依赖HAHAperflib的重新打包),而是重新开发了自己的堆转储解析器:SharkShark的使用提升了速度并减少了内存使用。额外代码主要来自Shark, 自动化测试和权限相关的UI代码。

下面我们将开始分析全新的,Kotlin版本的LeakCnary:

1. 如何查看源码

因为我们使用的2.2版本,没有显式的框架入口,无法使用AndroidStudio的关联功能,所有我们要自己手动找代码,那么如何找到LeakCanary相关代码呢,我们需要到Lib里面找:

  1. 在Project Pannel中选择 “Project”

  2. 点击"External Libraries"

  3. 下拉找到LeakCanary的包,展开就可以看到相关代码

查看代码

我们可以看到LeakCanary的不少包,主要包括:

  • leakcanary-android

    集成入口模块,提供 LeakCanary 安装,公开 API 等能力

  • leakcanary-android-process

    和 leakcanary-android 一样,区别是会在单独的进程进行分析

  • leakcanary-android-core

    核心模块

  • leakcanary-object-watcher-android,leakcanary-object-watcher-android-androidx,leakcanary-watcher-android-support-fragments

    对象实例观察模块,在 ActivityFragment 等对象的生命周期中,注册对指定对象实例的观察,有 ActivityFragmentFragment ViewViewModel

  • shark-android

    提供特定于 Android 平台的分析能力。例如设备的信息,Android 版本,已知的内存泄露问题等

  • shark

    hprof 文件解析与分析的入口模块

  • shark-graph

    分析堆中对象的关系图模块

  • shark-hprof

    解析 hprof 文件模块

  • shark-log

    日志模块

2. 源码分析

LeakCanary 2.0不需要添加代码便可以跟随APP启动,原理在于利用了ContentProvider的特性,ContentProvider.onCreate方法会先于Application.onCreate执行。具体的实现只需要在AndroidManifeat.xml中配置一下定制的ContentProvider,在其onCreate方法中通过install进行初始化初始化,便可以省去LeakCanary 1.6版本中在Application中install的步骤:

//注册ContentProvider @leakcanary-object-watcher-android/src/main/AndroidManifest.xml
<application>
    <provider
        android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
        android:authorities="${applicationId}.leakcanary-installer"
        android:exported="false"/>
  </application>

首先在AndroidManifest.xml中注册contentProvider,然后对contentProvider进行定义:

//@AppWatcherInstaller.kt
internal class LeakCanaryProcess : AppWatcherInstaller() {
    override fun onCreate(): Boolean {
      super.onCreate()
      AppWatcher.config = AppWatcher.config.copy(enabled = false)
      return true
    }
  }

  override fun onCreate(): Boolean {
  	//获取application
    val application = context!!.applicationContext as Application
    //-->2.1 加载LeakCanary
    InternalAppWatcher.install(application)
    return true
  }
}

//2.1 加载LeakCanary @InternalAppWatcher.kt
fun install(application: Application) {
	...
	//检查当前线程是否有主线程
    checkMainThread()
    if (this::application.isInitialized) {
      //如果LeakCanary已经加载过,直接放回
      return
    }
    InternalAppWatcher.application = application

    val configProvider = { AppWatcher.config }
    //-->2.1监视Activity
    ActivityDestroyWatcher.install(application, objectWatcher, configProvider)
    //-->2.2监视Fragment
    FragmentDestroyWatcher.install(application, objectWatcher, configProvider)
    //-->2.3调用上层模块InternalLeakCanary.invoke
    onAppWatcherInstalled(application)
  }
2.1 ActivityDestroyWatcher.install
// @ActivityDestroyWatcher.kt
companion object {
  fun install(
    application: Application,
    objectWatcher: ObjectWatcher,
    configProvider: () -> Config
  ) {
    //-->2.1.1 创建Activity destroy监听回调
    val activityDestroyWatcher =
      ActivityDestroyWatcher(objectWatcher, configProvider)
    //-->2.1.2 同Application绑定
    application.registerActivityLifecycleCallbacks(activityDestroyWatcher.lifecycleCallbacks)
  }
}

//2.1.1 创建Activity destroy监听回调
  private val lifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
      override fun onActivityDestroyed(activity: Activity) {
        //Activity destroy触发存在对象检查
        if (configProvider().watchActivities) {
          // -->2.1.2 objectWatcher监视activity
          objectWatcher.watch(
              activity, "${activity::class.java.name} received Activity#onDestroy() callback"
          )
        }
      }
    }

//2.1.2 objectWatcher监视activity
@Synchronized fun watch(
    watchedObject: Any,  //activity
    description: String
  ) {
    if (!isEnabled()) {
      return
    }
    //-->2.1.3将可达activity删除
    removeWeaklyReachableObjects()
    val key = UUID.randomUUID()
        .toString()
    
    val watchUptimeMillis = clock.uptimeMillis()
    //根据activity建对应的弱引用,并绑定ReferenceQueue
    val reference =
      KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
    ...
    //将reference保存到watchedObjects数组中
    watchedObjects[key] = reference
    //-->2.1.4 启动延时5s任务
    checkRetainedExecutor.execute {
      //-->2.1.5 获取GC无法回收的Activity
      moveToRetained(key)
    }
  }

//2.1.3将可达activity删除 @ObjectWatcher.kt
private fun removeWeaklyReachableObjects() {
    var ref: KeyedWeakReference?
    do {
      //重点,在GC或者finalization之前,在WeakReferences的被引用对象(这里是Activity)的可达性更改时,
      //会把WeakReferences添加到创建时候指定的ReferenceQueue队列,这些可达性变更得对象,就是内存不泄露对象
      ref = queue.poll() as KeyedWeakReference?
      if (ref != null) {
        //在watchedObjects中删除不发送内存泄漏对象,剩下内存泄漏对象
        watchedObjects.remove(ref.key)
      }
    } while (ref != null)
  }

 //2.1.4 启动延时5s任务 @ObjectWatcher.kt
  val watchDurationMillis: Long = TimeUnit.SECONDS.toMillis(5)	
  private val checkRetainedExecutor = Executor {
    //在主线程延时五秒执行任务
    mainHandler.postDelayed(it, AppWatcher.config.watchDurationMillis)
  }

 //2.1.5 获取GC无法回收的Activity @ObjectWatcher.kt
 @Synchronized private fun moveToRetained(key: String) {
    //-->2.1.3将可达activity删除
    removeWeaklyReachableObjects()
    val retainedRef = watchedObjects[key]
    if (retainedRef != null) {
      //保存当前时间作为泄漏时间
      retainedRef.retainedUptimeMillis = clock.uptimeMillis()
      //-->2.1.6 通知InternalLeakCanary发生内存泄漏
      onObjectRetainedListeners.forEach { it.onObjectRetained() }
    }
  } 

//2.1.6 通知InternalLeakCanary发生内存泄漏 @HeapDumpTrigger.kt
  override fun onObjectRetained() {
    if (this::heapDumpTrigger.isInitialized) {
      //-->2.1.7通知heapDumpTrigger有内存泄漏
      heapDumpTrigger.onObjectRetained()
    }
  }

  //2.1.7 通知heapDumpTrigger有内存泄漏 @HeapDumpTrigger.kt
  fun onObjectRetained() {
    //-->2.1.8 再次检查内存泄漏
    scheduleRetainedObjectCheck(
        reason = "found new object retained",
        rescheduling = false
    )
  }

//2.1.8 再次检查内存泄漏 @HeapDumpTrigger.kt
private fun scheduleRetainedObjectCheck(...) {
    ...
    backgroundHandler.postDelayed({
      checkScheduledAt = 0
      //-->2.1.9 检查泄漏对象
      checkRetainedObjects(reason)
    }, delayMillis)
  }

//2.1.9 检查泄漏对象 @HeapDumpTrigger.kt
private fun checkRetainedObjects(reason: String) {
	...
    if (retainedReferenceCount > 0) {
      //-->2.1.10 GC一次,确认所有存在对象都是泄漏对象
      gcTrigger.runGc()
      retainedReferenceCount = objectWatcher.retainedObjectCount
    }

    //-->2.1.11 检查当前存在对象的个数
    if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return

    if (!config.dumpHeapWhenDebugging && DebuggerControl.isDebuggerAttached) {
      ...
      //如果配置了debug不使用heap且正在debug,延时20s在执行checkRetainedObjects(reason)
      scheduleRetainedObjectCheck(
          reason = "debugger is attached",
          rescheduling = true,
          //WAIT_FOR_DEBUG_MILLIS为20s
          delayMillis = WAIT_FOR_DEBUG_MILLIS
      )
      return
    }

    val now = SystemClock.uptimeMillis()
    val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis
    //WAIT_BETWEEN_HEAP_DUMPS_MILLIS为60,60s内执行一次操作
    if (elapsedSinceLastDumpMillis < WAIT_BETWEEN_HEAP_DUMPS_MILLIS) { 
        ...
          delayMillis = WAIT_BETWEEN_HEAP_DUMPS_MILLIS - elapsedSinceLastDumpMillis
        ...
      return
    }
	//-->2.1.12 执行dump Heap操作
    dumpHeap(retainedReferenceCount, retry = true)
  }

  // 2.1.10 触发GC @GcTrigger.kt
  object Default : GcTrigger {
    override fun runGc() {
      //System.gc() 并不会每次都引起GC. Runtime.gc()会更有效
      Runtime.getRuntime()
          .gc()
     ...
    }
  }
      
//2.1.11 检查当前所有存在对象个数 @HeapDumpTrigger.kt
private fun checkRetainedCount(
    retainedKeysCount: Int,
    retainedVisibleThreshold: Int
  ): Boolean {
    val countChanged = lastDisplayedRetainedObjectCount != retainedKeysCount
    lastDisplayedRetainedObjectCount = retainedKeysCount
    if (retainedKeysCount == 0) {
      //存在对象为0
      return true
    }

    if (retainedKeysCount < retainedVisibleThreshold) {
      //存在对象低于阈值5个
      if (applicationVisible || applicationInvisibleLessThanWatchPeriod) {
        ...
        //当前应用可见,或者不可见时间间隔少于 5s,重新安排到2s后执行checkRetainedObjects
        scheduleRetainedObjectCheck(
            reason = "found only $retainedKeysCount retained objects (< $retainedVisibleThreshold while app visible)",
            rescheduling = true,
            delayMillis = WAIT_FOR_OBJECT_THRESHOLD_MILLIS
        )
        return true
      }
    }
    return false
  }   

在继续dumpHeap前,LeakCanary还做了如下操作:

  1. 首先获取存在对象的个数,如果大于0,则GC一次之后再次获取
  2. 如果步骤1后存在对象的个数小于5个,且应用可见,或者不可见时间小于5s,退出,定时2s后再次检查存在对象
  3. 如果步骤1后存在对象的个数大于等于5个,则继续执行下面的代码,准备dump heap
  4. 如果config里面配置的“调试时不允许dump heap”为false(默认值)且正在调试,退出,定时20s再次检查存在对象
  5. 如果DumpHeap的时间间隔不足60s,退出,并等间隔时间达到60s再次检查存在对象
  6. 如果函数没退出,开始dumpHeap

下面继续看dumpHeap的实现:

//2.1.12 执行dump Heap操作 @HeapDumpTrigger.kt
 private fun dumpHeap(
    retainedReferenceCount: Int,
    retry: Boolean
  ) {
	...
	//-->2.1.13 生成Heap文件
    val heapDumpFile = heapDumper.dumpHeap()
    ...
    //存在的对象已经dumpHeap,故不需要保留
    objectWatcher.clearObjectsWatchedBefore(heapDumpUptimeMillis)
    //-->2.4 分析Heap文件
    HeapAnalyzerService.runAnalysis(application, heapDumpFile)
  } 

//2.1.13 生成Heap文件 @AndroidHeapDumper
override fun dumpHeap(): File? {
    ...
    return try {
      //使用sdk提供的dumpHprofData生成Heap文件
      Debug.dumpHprofData(heapDumpFile.absolutePath)
      ...
    }
  }

至此,对Activity内存泄漏的监听注册到dump Heap过程源码分析完毕,接下来我们看看LeakCanaryFragment是如何操作的。

2.2 FragmentDestroyWatcher.install
//2.2监视Fragment
FragmentDestroyWatcher.install(application, objectWatcher, configProvider)

我们继续看Fragment对应的install处理

fun install(...) {
	//创建观察者集合
    val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
	//如果SDK大于等于O,则添加"android.app.Fragment"的观察者AndroidOFragmentDestroyWatcher
    if (SDK_INT >= O) {
      fragmentDestroyWatchers.add(
          AndroidOFragmentDestroyWatcher(objectWatcher, configProvider)
      )
    }

	//对"androidx.fragment.app.Fragment"添加观察
    getWatcherIfAvailable(
        ANDROIDX_FRAGMENT_CLASS_NAME,
        ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
        objectWatcher,
        configProvider
    )?.let {
      //-->2.2.1添加观察者AndroidXFragmentDestroyWatcher
      fragmentDestroyWatchers.add(it)
    }
	//对"android.support.v4.app.Fragment"添加观察
    getWatcherIfAvailable(
        ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
        ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
        objectWatcher,
        configProvider
    )?.let {
      //添加观察者AndroidSupportFragmentDestroyWatcher
      fragmentDestroyWatchers.add(it)
    }

	//如果观察列表为空,直接返回
    if (fragmentDestroyWatchers.size == 0) {
      return
    }

	//对所有Fragment进行监视
    application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
      override fun onActivityCreated(
        activity: Activity,
        savedInstanceState: Bundle?
      ) {
        for (watcher in fragmentDestroyWatchers) {
         //-->2.2.2触发观察者的invoke()方法
          watcher(activity)
        }
      }
    })
  }

watch(activity) 实际是对应kotlinFunctions.kt文件的Function1接口,P1ActivityRUnit即为Javavoid

package kotlin.jvm.functions

interface Function1<in P1, out R> : kotlin.Function<R> {
    fun invoke(p1: P1): R
}

也就是说,watch(activity)最终调用的是watcher中的invoke(Activity)方法

AndroidOFragmentDestroyWatcherAndroidXFragmentDestroyWatcherAndroidXFragmentDestroyWatcher源码非常类似,只是针对的Fragment不同而调用的API不同而已,下面以AndroidXFragmentDestroyWatcher为例看看里面是如何实现的。

//2.2.1添加观察 @AndroidXFragmentDestroyWatcher.kt
internal class AndroidXFragmentDestroyWatcher(
  private val objectWatcher: ObjectWatcher,
  private val configProvider: () -> Config
) : (Activity) -> Unit {

  private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {

    override fun onFragmentCreated(
      fm: FragmentManager,
      fragment: Fragment,
      savedInstanceState: Bundle?
    ) {
      ViewModelClearedWatcher.install(fragment, objectWatcher, configProvider)
    }

    override fun onFragmentViewDestroyed(
      fm: FragmentManager,
      fragment: Fragment
    ) {
      val view = fragment.view
      if (view != null && configProvider().watchFragmentViews) {
      	// -->2.1.2 objectWatcher监视view
        objectWatcher.watch(
            view, "${fragment::class.java.name} received Fragment#onDestroyView() callback " +
            "(references to its views should be cleared to prevent leaks)"
        )
      }
    }

    override fun onFragmentDestroyed(
      fm: FragmentManager,
      fragment: Fragment
    ) {
      if (configProvider().watchFragments) {
      	// -->2.1.2 objectWatcher监视view
        objectWatcher.watch(
            fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
        )
      }
    }
  }

  //2.2.2触发观察者的invoke()方法
  override fun invoke(activity: Activity) {
    if (activity is FragmentActivity) {
      val supportFragmentManager = activity.supportFragmentManager
      //-->2.2.3注册监听fragment生命周期回调
      supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
      ViewModelClearedWatcher.install(activity, objectWatcher, configProvider)
    }
  }
}

WatcherActivityFragmentManager注册FragmentLifecycleCallbacks,这样在Fragment调用onDestroyViewonDestory之后就能观察FragmentView或者Fragment本身是否存在泄漏。将Fragment进行监视之后的流程同Activity,可以参考2.1节的分析。

2.3 onAppWatcherInstalled
//2.3 @InternalAppWatcher.kt 
init {
    val internalLeakCanary = try {
      val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
      leakCanaryListener.getDeclaredField("INSTANCE")
          .get(null)
    } catch (ignored: Throwable) {
      NoLeakCanary
    }
    @kotlin.Suppress("UNCHECKED_CAST")
    onAppWatcherInstalled = internalLeakCanary as (Application) -> Unit
  }

internalLeakCanary是一个方法对象,这个对象的值是通过反射获取的 InternalLeakCanary.INSTANCE ,它是一个单例对象。InternalLeakCanary 位于 leakcanary-android-core 模块,这也是需要反射的原因。

install中调用onAppWatcherInstalled(application), 同2.2提到的watch(activity),实际是对应kotlinFunctions.kt文件的Function1接口,P1ApplicationRUnit即为Javavoid

也就是onAppWatcherInstalled(application) 实际调用的是InternalLeakCanary.invoke方法:

//@InternalLeakCanary.kt
override fun invoke(application: Application) {
    this.application = application
	//2.3.1 添加内存泄漏监听,方便objectWatcher通知InternalLeakCanary
    AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
	//初始化heapDumper,用于生成heap文件
    val heapDumper = AndroidHeapDumper(application, leakDirectoryProvider)
	//指定GC策略
    val gcTrigger = GcTrigger.Default

    val configProvider = { LeakCanary.config }
	//创建线程
    val handlerThread = HandlerThread(LEAK_CANARY_THREAD_NAME)
    handlerThread.start()
    val backgroundHandler = Handler(handlerThread.looper)
	//初始化heapDumpTrigger
    heapDumpTrigger = HeapDumpTrigger(
        application, backgroundHandler, AppWatcher.objectWatcher, gcTrigger, heapDumper,
        configProvider
    )
    //监听application是否可见
    application.registerVisibilityListener { applicationVisible ->
      this.applicationVisible = applicationVisible
      heapDumpTrigger.onApplicationVisibilityChanged(applicationVisible)
    }
    //监听Activity Resume
    registerResumedActivityListener(application)
    //创建动态快捷方式
    addDynamicShortcut(application)

    disableDumpHeapInTests()
  }

基本上InternalLeakCanary.init将后续监视和生成Heap文件需要用到的文件进行了初始化,写在install之后方便大家都流程有更深刻的理解。

2.4 HeapAnalyzerService.runAnalysis
//2.4 分析Heap文件 @HeapDumpTrigger.kt
HeapAnalyzerService.runAnalysis(application, heapDumpFile)

下面我们对runAnalysis流程进行分析:

internal class HeapAnalyzerService : ForegroundService(
    HeapAnalyzerService::class.java.simpleName,
    R.string.leak_canary_notification_analysing,
    R.id.leak_canary_notification_analyzing_heap
), OnAnalysisProgressListener {

  override fun onHandleIntentInForeground(intent: Intent?) {
	...
	  //-->2.4.1在service中分析Heap文件
      analyzeHeap(heapDumpFile, config)
	...
  }

  //2.4.1在service中分析Heap文件
  private fun analyzeHeap(...): HeapAnalysis {
    val heapAnalyzer = HeapAnalyzer(this)

    //对混淆的代码进行支持
    val proguardMappingReader = try {
      ProguardMappingReader(assets.open(PROGUARD_MAPPING_FILE_NAME))
    } catch (e: IOException) {
      null
    }
    //-->2.4.2 heapAnalyzer对Heap文件进行分析
    return heapAnalyzer.analyze(
        heapDumpFile = heapDumpFile,
        leakingObjectFinder = config.leakingObjectFinder,
        referenceMatchers = config.referenceMatchers,
        computeRetainedHeapSize = config.computeRetainedHeapSize,
        objectInspectors = config.objectInspectors,
        metadataExtractor = config.metadataExtractor,
        proguardMapping = proguardMappingReader?.readProguardMapping()
    )
  }

  companion object {
  	...
    fun runAnalysis(... ) {
      val intent = Intent(context, HeapAnalyzerService::class.java)
      intent.putExtra(HEAPDUMP_FILE_EXTRA, heapDumpFile)
      startForegroundService(context, intent)
    }

    private fun startForegroundService(
      context: Context,
      intent: Intent
    ) {
      //在Android O之后 使用前台服务进行分析
      if (SDK_INT >= 26) {
        context.startForegroundService(intent)
      } else {
        //在Android O之前 使用后台服务进行分析
        context.startService(intent)
      }
    }
  }
}

//2.4.2 heapAnalyzer对Heap文件进行分析 @HeapAnalyzer.kt
fun analyze(...): HeapAnalysis {
    ...
    return try {
      listener.onAnalysisProgress(PARSING_HEAP_DUMP)
      Hprof.open(heapDumpFile)
          .use { hprof ->
          	//生成heap graph, 用于表示heap中的对象关系图
            val graph = HprofHeapGraph.indexHprof(hprof, proguardMapping)
            //初始化FindLeakInput
            val helpers =
              FindLeakInput(graph, referenceMatchers, computeRetainedHeapSize, objectInspectors)
            //-->2.4.3 分析heap graph
            helpers.analyzeGraph(
                metadataExtractor, leakingObjectFinder, heapDumpFile, analysisStartNanoTime
            )
          }
    }
    ...
  }
  
  //2.4.3 分析heap graph @HeapAnalyzer.kt
    private fun FindLeakInput.analyzeGraph(...): HeapAnalysisSuccess {
    listener.onAnalysisProgress(EXTRACTING_METADATA)
    //提取graph的metadata数据
    val metadata = metadataExtractor.extractMetadata(graph)
    listener.onAnalysisProgress(FINDING_RETAINED_OBJECTS)
    //获取泄露对象的 objectIds
    val leakingObjectIds = leakingObjectFinder.findLeakingObjectIds(graph)
	//-->2.4.4 生成泄露对象报告
    val (applicationLeaks, libraryLeaks) = findLeaks(leakingObjectIds)

    return HeapAnalysisSuccess(...)
  }
  
  //2.4.4 生成泄露对象报告
  //共有两种泄漏类型:ApplicationLeak 和 LibraryLeak
  private fun FindLeakInput.findLeaks(leakingObjectIds: Set<Long>): Pair<List<ApplicationLeak>, List<LibraryLeak>> {
    val pathFinder = PathFinder(graph, listener, referenceMatchers)
    //查询泄露对象到 GC Roots 的路径
    val pathFindingResults =
      pathFinder.findPathsFromGcRoots(leakingObjectIds, computeRetainedHeapSize)
    return buildLeakTraces(pathFindingResults)
  }

内存分析设计到LeakCanary自身设计的Shark架构,相关信息可以参考官网

小结

通过阅读源码,我们可以看到LeakCanary的核心逻辑在于利用ReferenceQueueWeakReferences可达性改变进行监听,获取发送内存泄漏的对象,同时使用自己的Shark对Heap文件进行分析,进而为使用者提供了一个可视化的内存优化神器,我们也可以看到做了对于是否为为内存泄漏的判断十分严谨,又是GC又是延时。

在明白获取内存泄漏信息机制的同时,我们也明白,该机制只对Java层起作用,而Native层并不在检查范围。

参考

LeakCanary Change Log

LeakCanary 2.0原理

LeakCanary2 源码分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值