LeakCanary 原理分析

Posted 清浅岁月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeakCanary 原理分析相关的知识,希望对你有一定的参考价值。

LeakCanary 原理分析

LeakCanary的初始化

LeakCanary2.3的引入:

    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'

2.3版本无需在Application中做额外操作。

深入了解一下具体是如何初始化的,我的是2.3版本的,2.0以下版本应该和这个不一样:

https://github.com/square/leakcanary/blob/main/leakcanary-object-watcher-android/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.squareup.leakcanary.objectwatcher"
    >

  <application>
    <provider
        android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
        android:authorities="$applicationId.leakcanary-installer"
        android:enabled="@bool/leak_canary_watcher_auto_install"
        android:exported="false"/>
  </application>
</manifest>

在该lib下的AppWatcherInstaller的代码如下:

package leakcanary.internal

import android.app.Application
import android.content.ContentProvider
import android.content.ContentValues
import android.database.Cursor
import android.net.Uri
import leakcanary.AppWatcher

/**
 * Content providers are loaded before the application class is created. [AppWatcherInstaller] is
 * used to install [leakcanary.AppWatcher] on application start.
 */
internal sealed class AppWatcherInstaller : ContentProvider() 

  /**
   * [MainProcess] automatically sets up the LeakCanary code that runs in the main app process.
   */
  internal class MainProcess : AppWatcherInstaller()

  /**
   * When using the `leakcanary-android-process` artifact instead of `leakcanary-android`,
   * [LeakCanaryProcess] automatically sets up the LeakCanary code
   */
  internal class LeakCanaryProcess : AppWatcherInstaller() 
    override fun onCreate(): Boolean 
      super.onCreate()
      AppWatcher.config = AppWatcher.config.copy(enabled = false)
      return true
    
  

  override fun onCreate(): Boolean 
    val application = context!!.applicationContext as Application
    InternalAppWatcher.install(application)   // 重点在这里
    return true
  

  override fun query(
    uri: Uri,
    strings: Array<String>?,
    s: String?,
    strings1: Array<String>?,
    s1: String?
  ): Cursor? 
    return null
  
  
  
		....

是通过ContentProvider来实现的,ContentProvider的初始化要比application的oncreate方法还要早一些。
InternalAppWatcher.install(application)中具体的内容:


 fun install(application: Application) 
    SharkLog.logger = DefaultCanaryLog()
    checkMainThread()
    if (this::application.isInitialized) 
      return
    
    InternalAppWatcher.application = application

    val configProvider =  AppWatcher.config 
    ActivityDestroyWatcher.install(application, objectWatcher, configProvider)
    FragmentDestroyWatcher.install(application, objectWatcher, configProvider)
    onAppWatcherInstalled(application)
  
  

做了activity与fragment的检测的初始化,和onAppWatcherInstalled。

先看一下activity的监听。

/*
 * Copyright (C) 2015 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package leakcanary.internal

import android.app.Activity
import android.app.Application
import leakcanary.AppWatcher.Config
import leakcanary.ObjectWatcher
import leakcanary.internal.InternalAppWatcher.noOpDelegate

internal class ActivityDestroyWatcher private constructor(
  private val objectWatcher: ObjectWatcher,
  private val configProvider: () -> Config
) 

  private val lifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks by noOpDelegate() 
      override fun onActivityDestroyed(activity: Activity) 
        if (configProvider().watchActivities) 
          objectWatcher.watch(
              activity, "$activity::class.java.name received Activity#onDestroy() callback"
          )
        
      
    

  companion object 
    fun install(
      application: Application,
      objectWatcher: ObjectWatcher,
      configProvider: () -> Config
    ) 
      val activityDestroyWatcher =
        ActivityDestroyWatcher(objectWatcher, configProvider)
      application.registerActivityLifecycleCallbacks(activityDestroyWatcher.lifecycleCallbacks)
    
  


根据lifecycle,根据application注册registerActivityLifecycleCallbacks接口,使用objectWatcher.watch进行检测。

再看看Fragment的检测,fragment的检测比较麻烦。

/*
 * Copyright (C) 2019 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package leakcanary.internal

import android.app.Activity
import android.app.Application
import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES.O
import android.os.Bundle
import leakcanary.AppWatcher
import leakcanary.ObjectWatcher
import leakcanary.internal.InternalAppWatcher.noOpDelegate

/**
 * Internal class used to watch for fragments leaks.
 */
internal object FragmentDestroyWatcher 

  private const val ANDROIDX_FRAGMENT_CLASS_NAME = "androidx.fragment.app.Fragment"
  private const val ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME =
    "leakcanary.internal.AndroidXFragmentDestroyWatcher"

  // Using a string builder to prevent Jetifier from changing this string to Android X Fragment
  @Suppress("VariableNaming", "PropertyName")
  private val ANDROID_SUPPORT_FRAGMENT_CLASS_NAME =
    StringBuilder("android.").append("support.v4.app.Fragment")
        .toString()
  private const val ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME =
    "leakcanary.internal.AndroidSupportFragmentDestroyWatcher"

  fun install(
    application: Application,
    objectWatcher: ObjectWatcher,
    configProvider: () -> AppWatcher.Config
  ) 
    val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()

    if (SDK_INT >= O) 
      fragmentDestroyWatchers.add(
          AndroidOFragmentDestroyWatcher(objectWatcher, configProvider)
      )
    

    getWatcherIfAvailable(
        ANDROIDX_FRAGMENT_CLASS_NAME,
        ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
        objectWatcher,
        configProvider
    )?.let 
      fragmentDestroyWatchers.add(it)
    

    getWatcherIfAvailable(
        ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
        ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
        objectWatcher,
        configProvider
    )?.let 
      fragmentDestroyWatchers.add(it)
    

    if (fragmentDestroyWatchers.size == 0) 
      return
    

    application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks by noOpDelegate() 
      override fun onActivityCreated(
        activity: Activity,
        savedInstanceState: Bundle?
      ) 
        for (watcher in fragmentDestroyWatchers) 
          watcher(activity)
        
      
    )
  


......





应该是根据activity获取一个fragmentDestroyWatcher的集合,给activity加载的每一个fragment创建一个监听器。

最后也是给每一个监听器注册LifecycleCallback将activity的生命周期回传到fragment的监听器中。

看一下fragment的具体的监听器度做了什么工作:

/*
 * Copyright (C) 2018 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
@file:Suppress("DEPRECATION")

package leakcanary.internal

import android.annotation.SuppressLint
import android.app.Activity
import android.app.Fragment
import android.app.FragmentManager
import leakcanary.AppWatcher.Config
import leakcanary.ObjectWatcher

@SuppressLint("NewApi")
internal class AndroidOFragmentDestroyWatcher(
  private val objectWatcher: ObjectWatcher,
  private val configProvider: () -> Config
) : (Activity) -> Unit 
  private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() 

    override fun onFragmentViewDestroyed(
      fm: FragmentManager,
      fragment: Fragment
    ) 
      val view = fragment.view
      if (view != null && configProvider().watchFragmentViews) 
        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) 
        objectWatcher.watch(
            fragment, "$fragment::class.java.name received Fragment#onDestroy() callback"
        )
      
    
  

  override fun invoke(activity: Activity) 
    val fragmentManager = activity.fragmentManager
    fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
  



注册fragment的LifecycleCallbacks回调,在fragmen 的onFragmentDestroyed和onFragmentViewDestroyed中使用objectWatcher.watch做了检测。

在看一下onAppWatcherInstalled做了什么:

  private val onAppWatcherInstalled: (Application) -> Unit


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做多了什么操作:

internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener 


override fun invoke(application: Application) 
    this.application = application

    checkRunningInDebuggableBuild()

    AppWatcher.objectWatcher.addOnObjectRetainedListener(this)

    val heapDumper = AndroidHeapDumper(application, leakDirectoryProvider)

    val gcTrigger = GcTrigger.Default

    val configProvider =  LeakCanary.config 

    val handlerThread = HandlerThread(LEAK_CANARY_THREAD_NAME)
    handlerThread.start()
    val backgroundHandler = Handler(handlerThread.looper)

    heapDumpTrigger = HeapDumpTrigger(
        application, backgroundHandler, AppWatcher.objectWatcher, gcTrigger, heapDumper,
        configProvider
    )
    application.registerVisibilityListener  applicationVisible ->
      this.applicationVisible = applicationVisible
      heapDumpTrigger.onApplicationVisibilityChanged(applicationVisible)
    
    registerResumedActivityListener(application)
    addDynamicShortcut(application)

    disableDumpHeapInTests()
  

.....


override fun onObjectRetained() 
    if (this::heapDumpTrigger.isInitialized) 
      heapDumpTrigger.onObjectRetained()
    
  
  
  
.......




添加addOnObjectRetainedListener,heapDumper,gcTrigger,handlerThread等一些准备工作。初始化工作基本完成了。

下面具体看一下objectWatcher.watch中具体是怎么做检测的,objectWatcher中的代码有点多,想看直接可以在这里看

https://github.com/square/leakcanary/blob/main/leakcanary-object-watcher/src/main/java/leakcanary/ObjectWatcher.kt

   */
  @Synchronized fun watch(
    watchedObject: Any,
    description: String
  ) 
    if (!isEnabled()) 
      return
    
    removeWeaklyReachableObjects()
    val key = UUID.randomUUID()
        .toString()
    val watchUptimeMillis = clock.uptimeMillis()
    val reference =
      KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
    SharkLog.d 
      "Watching " +
          (if (watchedObject is Class<*>) watchedObject.toString() else "instance of $watchedObject.javaClass.name") +
          (if (description.isNotEmpty()) " ($description)" else "") +
          " with key $key"
    

    watchedObjects[key] = reference
    checkRetainedExecutor.execute 
      moveToRetained(key)
    
  
  
  ......
  
 @Synchronized private fun moveToRetained(key: String) 
    removeWeaklyReachableObjects()
    val retainedRef = watchedObjects[key]
    if (retainedRef != null) 
      retainedRef.retainedUptimeMillis = clock.uptimeMillis()
      onObjectRetainedListeners.forEach  it.onObjectRetained() 
    
  
  
  


最后 moveToRetained执行onObjectRetainedListeners集合中的onObjectRetained()方法。onObjectRetained()方法既InternalLeakCanary重写的那个方法,这个方法中如何处理的:

InternalLeakCanary的onObjectRetained方法


 override fun onObjectRetained() 
    if (this::heapDumpTrigger.isInitialized) 
      heapDumpTrigger.onObjectRetained()
    
  

HeapDumpTrigger的onObjectRetained和scheduleRetainedObjectCheck方法


  fun onObjectRetained() 
    scheduleRetainedObjectCheck(
        reason = "found new object retained",
        rescheduling = false
    )
  
  
  
  
   private fun scheduleRetainedObjectCheck(
    reason: String,
    rescheduling: Boolean,
    delayMillis: Long = 0L
  ) 
    val checkCurrentlyScheduledAt = checkScheduledAt
    if (checkCurrentlyScheduledAt > 0) 
      val scheduledIn = checkCurrentlyScheduledAt - SystemClock.uptimeMillis()
      SharkLog.d  "Ignoring request to check for retained objects ($reason), already scheduled in $scheduledInms" 
      return
     else 
      val verb = if (rescheduling) "Rescheduling" else "Scheduling"
      val delay = if (delayMillis > 0) " in $delayMillisms" else ""
      SharkLog.d  "$verb check for retained objects$delay because $reason" 
    
    checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
    backgroundHandler.postDelayed(
      checkScheduledAt = 0
      checkRetainedObjects(reason)
    , delayMillis)
  
  
  

核心在checkRetainedObjects方法中:


  private fun checkRetainedObjects(reason: String) 
    val config = configProvider()
    // A tick will be rescheduled when this is turned back on.
    if (!config.dumpHeap) 
      SharkLog.d  "Ignoring check for retained objects scheduled because $reason: LeakCanary.Config.dumpHeap is false" 
      return
    

    var retainedReferenceCount = objectWatcher.retainedObjectCount

    if (retainedReferenceCount > 0) 
      gcTrigger.runGc()
      retainedReferenceCount = objectWatcher.retainedObjectCount
    

    if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return

    if (!config.dumpHeapWhenDebugging && DebuggerControl.isDebuggerAttached) 
      onRetainInstanceListener.onEvent(DebuggerIsAttached)
      showRetainedCountNotification(
          objectCount = retainedReferenceCount,
          contentText = application.getString(
              R.string.leak_canary_notification_retained_debugger_attached
          )
      )
      scheduleRetainedObjectCheck(
          reason = "debugger is attached",
          rescheduling = true,
          delayMillis = WAIT_FOR_DEBUG_MILLIS
      )
      return
    

    val now = SystemClock.uptimeMillis()
    val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis
    if (elapsedSinceLastDumpMillis < WAIT_BETWEEN_HEAP_DUMPS_MILLIS) 
      onRetainInstanceListener.onEvent(DumpHappenedRecently)
      showRetainedCountNotification(
          objectCount = retainedReferenceCount,
          contentText = application.getString(R.string.leak_canary_notification_retained_dump_wait)
      )
      scheduleRetainedObjectCheck(
          reason = "previous heap dump was $elapsedSinceLastDumpMillisms ago (< $WAIT_BETWEEN_HEAP_DUMPS_MILLISms)",
          rescheduling = true,
          delayMillis = WAIT_BETWEEN_HEAP_DUMPS_MILLIS - elapsedSinceLastDumpMillis
      )
      return
    

    SharkLog.d  "Check for retained objects found $retainedReferenceCount objects, dumping the heap" 
    dismissRetainedCountNotification()
    dumpHeap(retainedReferenceCount, retry = true)
  

最后生成dumpHeap信息


private fun dumpHeap(
    retainedReferenceCount: Int,
    retry: Boolean
  ) 
    saveResourceIdNamesToMemory()
    val heapDumpUptimeMillis = SystemClock.uptimeMillis()
    KeyedWeakReference.heapDumpUptimeMillis = heapDumpUptimeMillis
    val heapDumpFile = heapDumper.dumpHeap()
    if (heapDumpFile == null) 
      if (retry) 
        SharkLog.d  "Failed to dump heap, will retry in $WAIT_AFTER_DUMP_FAILED_MILLIS ms" 
        scheduleRetainedObjectCheck(
            reason = "failed to dump heap",
            rescheduling = true,
            delayMillis = WAIT_AFTER_DUMP_FAILED_MILLIS
        )
       else 
        SharkLog.d  "Failed to dump heap, will not automatically retry" 
      
      showRetainedCountNotification(
          objectCount = retainedReferenceCount,
          contentText = application.getString(
              R.string.leak_canary_notification_retained_dump_failed
          )
      )
      return
    
    lastDisplayedRetainedObjectCount = 0
    lastHeapDumpUptimeMillis = SystemClock.uptimeMillis()
    objectWatcher.clearObjectsWatchedBefore(heapDumpUptimeMillis)
    HeapAnalyzerService.runAnalysis(application, heapDumpFile)
  

之后是对生成的文件进行分析HeapAnalyzerService.runAnalysis(application, heapDumpFile):
HeapAnalyzerService是一个前台service,启动service开始分析文件。

 fun runAnalysis(
      context: Context,
      heapDumpFile: File
    ) 
      val intent = Intent(context, HeapAnalyzerService::class.java)
      intent.putExtra(HEAPDUMP_FILE_EXTRA, heapDumpFile)
      startForegroundService(context, intent)
    


启动service后进行处理。

  override fun onHandleIntentInForeground(intent: Intent?) 
    if (intent == null || !intent.hasExtra(HEAPDUMP_FILE_EXTRA)) 
      SharkLog.d  "HeapAnalyzerService received a null or empty intent, ignoring." 
      return
    

    // Since we're running in the main process we should be careful not to impact it.
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)
    val heapDumpFile = intent.getSerializableExtra(HEAPDUMP_FILE_EXTRA) as File

    val config = LeakCanary.config
    val heapAnalysis = if (heapDumpFile.exists()) 
      analyzeHeap(heapDumpFile, config)
     else 
      missingFileFailure(heapDumpFile)
    
    onAnalysisProgress(REPORTING_HEAP_ANALYSIS)
    config.onHeapAnalyzedListener.onHeapAnalyzed(heapAnalysis)
  

  private fun analyzeHeap(
    heapDumpFile: File,
    config: Config
  ): HeapAnalysis 
    val heapAnalyzer = HeapAnalyzer(this)

    val proguardMappingReader = try 
      ProguardMappingReader(assets.open(PROGUARD_MAPPING_FILE_NAME))
     catch (e: IOException) 
      null
    
    return heapAnalyzer.analyze(
        heapDumpFile = heapDumpFile,
        leakingObjectFinder = config.leakingObjectFinder,
        referenceMatchers = config.referenceMatchers,
        computeRetainedHeapSize = config.computeRetainedHeapSize,
        objectInspectors = config.objectInspectors,
        metadataExtractor = config.metadataExtractor,
        proguardMapping = proguardMappingReader?.readProguardMapping()
    )
  

首先判断,文件是否存在,不存在按miss处理,存在进行分析,具体的分析。

dump对象及分析
dump对象

hprof是JDK提供的一种JVM TI Agent native工具。JVM TI,全拼是JVM Tool interface,是JVM提供的一套标准的C/C++编程接口,是实现Debugger、Profiler、Monitor、Thread Analyser等工具的统一基础,在主流Java虚拟机中都有实现。hprof工具事实上也是实现了这套接口,可以认为是一套简单的profiler agent工具。我们在新知周推:10.8-10.14(启动篇)中也提到过,可以参考其中美团的文章。

用过Android Studio Profiler工具的同学对hprof文件都不会陌生,当我们使用Memory Profiler工具的Dump Java heap图标的时候,profiler工具就会去捕获你的内存分配情况。但是捕获以后,只有在Memory Profiler正在运行的时候我们才能查看,那么我们要怎么样去保存当时的内存使用情况呢,又或者我想用别的工具来分析堆分配情况呢,这时候hprof文件就派上用场了。Android Studio可以把这些对象给export到hprof文件中去。

LeakCanary也是使用的hprof文件进行对象存储。hprof文件比较简单,整体按照 前置信息 + 记录表的格式来组织的。但是记录的种类相当之多。具体种类可以查看HPROF Agent。

同时,android中也提供了一个简便的方法Debug.dumphprofData(filePath)可以把对象dump到指定路径下的hprof文件中。LeakCanary使用使用Shark库来解析Hprof文件中的各种record,比较高效,使用Shark中的HprofReader和HprofWriter来进行读写解析,获取我们需要的信息。大家可以关注一些比较重要的,比如:

Class Dump
Instance Dump
Object Array Dump
Primitive Array Dump
dump具体的代码在AndroidHeapDumper类中。HprofReader和HprofWriter过于复杂,有兴趣的直接查看源码吧。


 return try 
      listener.onAnalysisProgress(PARSING_HEAP_DUMP)
      Hprof.open(heapDumpFile)
          .use  hprof ->
            val graph = HprofHeapGraph.indexHprof(hprof, proguardMapping)
            val helpers =
              FindLeakInput(graph, referenceMatchers, computeRetainedHeapSize, objectInspectors)
            helpers.analyzeGraph(
                metadataExtractor, leakingObjectFinder, heapDumpFile, analysisStartNanoTime
            )
          
     catch (exception: Throwable) 
      HeapAnalysisFailure(
          heapDumpFile, System.currentTimeMillis(), since(analysisStartNanoTime),
          HeapAnalysisException(exception)
      )
    
    
    
    其中的核心方法
    
     private fun FindLeakInput.analyzeGraph(
    metadataExtractor: MetadataExtractor,
    leakingObjectFinder: LeakingObjectFinder,
    heapDumpFile: File,
    analysisStartNanoTime: Long
  ): HeapAnalysisSuccess 
    listener.onAnalysisProgress(EXTRACTING_METADATA)
    val metadata = metadataExtractor.extractMetadata(graph)

    listener.onAnalysisProgress(FINDING_RETAINED_OBJECTS)
    val leakingObjectIds = leakingObjectFinder.findLeakingObjectIds(graph)

    val (applicationLeaks, libraryLeaks) = findLeaks(leakingObjectIds)

    return HeapAnalysisSuccess(
        heapDumpFile = heapDumpFile,
        createdAtTimeMillis = System.currentTimeMillis(),
        analysisDurationMillis = since(analysisStartNanoTime),
        metadata = metadata,
        applicationLeaks = applicationLeaks,
        libraryLeaks = libraryLeaks
    )
  


首先调用HprofHeapGraph.indexHprof方法,这个方法会把dump出来的各种实例instance,Class类对象和Array对象等都建立起查询的索引,以record的id作为key,把需要的信息都存储在Map中便于后续取用
调用findLeakInput.findLeak方法,这个方法会从GC Root开始查询,找到最短的一条导致泄露的引用链,然后再根据这条引用链构建出LeakTrace。
把查询出来的LeakTrace对外展示

最后返回分析成功的HeapAnalysisSuccess对象将数据在log中打印,或者通知栏通知。

总结:

  1. LeakCanary的初始化,使用ContentProvider
  2. 添加fragment与activity的监听,在onDestory的触发ObjectWatcher的检测
  3. ObjectWatcher使用HeapDumpTrigger,产生dumpHprof文件
  4. 使用HeapAnalyzerService对dumpHprof进行分析
  5. HeapAnalyzerService使用sharklib调用jvm的TI
  6. sharklib使用HprofHeapGraph.indexHprof建立起索引,以record的id作为key存储map,findLeakInput.findLeak从gc节点查询找到最短引用链构建出LeakTrace
  7. 最后生成一个AnalyzerSucess对象将上述信息封装,分发出来。

参考文档:https://www.jianshu.com/p/e36d60ab7ad2

以上是关于LeakCanary 原理分析的主要内容,如果未能解决你的问题,请参考以下文章

leakcanary原理分析

leakcanary原理分析

leakcanary原理分析

LeakCanary 2.0原理分析

LeakCanary 2.0原理分析

LeakCanary 内存泄露监测原理研究