LeakCanary2.x 源码解析

leakcanary2.x 源码解析

一、导读

在阅读源码前,请大家思考以下几个问题

1.它是如何做到仅一行配置代码就完成监控的,接入leakcanary并没有写任何代码,它是如何运行起来的?

2.它是在什么时机,去判断是否存在内存泄露的

3.它是通过什么原理,来判断是否存在内存泄露的

二、源码解析

2.1 接入

dependencies {
    ...接入方式
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
}
<application>
	...
//解压apk,看到接入新版本的LeakCanary的Manifest文件中生成了如下的provider
    <provider
        android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
        android:exported="false"
        <!-- SDK类可以学习这种占位符的方式,降低接入方的接入成本-->     
        <!-- android:authorities="${applicationId}.leakcanary-installer"-->
        android:authorities="com.vivo.website.gdpr.leakcanary-installer" />
</application>

知识点:

1.ContentProvider的onCreate的调用时机是在application onCreate之前调用的,即在应用启动时,完成了自身代码的调用,降低了接入方在java代码层面上的接入成本

2.通过占位符的方式,简化了接入方在manifest文件上的接入成本

3.debugImplementation 仅在debug模式下生效,降低了使用implementation时需要依赖空包的接入成本

2.2 监控时机

internal sealed class AppWatcherInstaller : ContentProvider() {

//provider的onC方法中,调用了install方法
  override fun onCreate(): Boolean {
    val application = context!!.applicationContext as Application
    InternalAppWatcher.install(application)
    return true
  }
    
}

知识点:现在一些新的组件,都由java代码切到了kotlin 上来,对于还未学习kotlin的同学来说,在AS中,可以通过查看对应类的class文件,反编译为java查看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iuxM1Aim-1594300470721)(C:\Users\11070535\AppData\Roaming\Typora\typora-user-images\1592035574741.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SWag20Uq-1594300470723)(C:\Users\11070535\AppData\Roaming\Typora\typora-user-images\1592035595332.png)]

internal object InternalAppWatcher {
   //...
  fun install(application: Application) {
    SharkLog.logger = DefaultCanaryLog()
    checkMainThread()
    if (this::application.isInitialized) {
      return
    }
    InternalAppWatcher.application = application

    val configProvider = { AppWatcher.config }
    // 监控activity的内存泄漏
    ActivityDestroyWatcher.install(application, objectWatcher, configProvider)
    // 监控fragment的内存泄漏
    FragmentDestroyWatcher.install(application, objectWatcher, configProvider)
    onAppWatcherInstalled(application)
  }
   //...
    
}
   

2.2.1Activity的内存泄露监测

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

  //
  private val lifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
        
      //activity destory 的时候,对Activity watch
      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中注册 ActivityLifecycleCallbacks  
        application.registerActivityLifecycleCallbacks(activityDestroyWatcher.lifecycleCallbacks)
    }
  }
}

**监控activity:**主要通过在Application中注册registerActivityLifecycleCallbacks绑定Activity生命周期回调,并在Activity destory时,调用ObjectWatcher的watch方法进行检测,ObjectWatcher会在稍后讲到

2.2.2 Fragment的内存泄露监测

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

  if (SDK_INT >= O) {
       // 添加对android.app.Fragment的支持
    fragmentDestroyWatchers.add(
        AndroidOFragmentDestroyWatcher(objectWatcher, configProvider)
    )
  }

    
     // 如果使用了AndroidX库,添加对androidx.fragment.app.Fragment的支持,同时支持了viewmodel
  getWatcherIfAvailable(
      ANDROIDX_FRAGMENT_CLASS_NAME,
      ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
      objectWatcher,
      configProvider
  )?.let {
    fragmentDestroyWatchers.add(it)
  }

    
     // 如果使用support库,添加对support.v4.app.Fragment的支持
  getWatcherIfAvailable(
      ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
      ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
      objectWatcher,
      configProvider
  )?.let {
    fragmentDestroyWatchers.add(it)
  }

  if (fragmentDestroyWatchers.size == 0) {
    return
  }

     // 注册Activity生命周期监听
  application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
    override fun onActivityCreated(
      activity: Activity,
      savedInstanceState: Bundle?
    ) {
         // 在onActivityCreated回调中,依次对各Watcher进行初始化
      for (watcher in fragmentDestroyWatchers) {
        watcher(activity)
      }
    }
  })
}

fragment 比较特殊,LeakCanary针对android.app.Fragment 、support.v4.app.Fragment、androidx.fragment.app.Fragment 三种fragment,分别通过AndroidOFragmentDestroyWatcher、AndroidSupportFragmentDestroyWatcherAndroidXFragmentDestroyWatcher来进行监听支持

//internal class AndroidOFragmentDestroyWatcher(
 
  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)
  }

监控android.app.Fragment:AndroidOFragmentDestroyWatcher类中,主要通过在Activity中注册注册FragmentLifecycleCallbacks回调,

当触发onFragmentViewDestroyed回调时,通过ObjectWatcher#watch检查fragment.mView对象(即Fragment#onCreateView创建的View)。

当触发onFragmentDestroyed回调时,检查fragment对象是否泄漏。

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) {
        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) {
    if (activity is FragmentActivity) {
      val supportFragmentManager = activity.supportFragmentManager
      supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
      ViewModelClearedWatcher.install(activity, objectWatcher, configProvider)
    }
  }
}

监控androidx.fragment.app.Fragment:AndroidXFragmentDestroyWatcherr类中,主要通过在Activity中注册supportFragmentManager注册LifecycleCallbacks监听Fragment生命周期。

同android Fragment的监听一样,在onFragmentViewDestroyed检测View,在onFragmentDestroyed检测Fragment。

有一点不同的是,AndroidXFragmentDestroyWatcher在onFragmentCreated回调中,还会初始化ViewModel的监听。当ViewModel执行clear触发onCleared回调时,会检测ViewModel是否泄漏。

internal class AndroidSupportFragmentDestroyWatcher(
  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) {
    if (activity is FragmentActivity) {
      val supportFragmentManager = activity.supportFragmentManager
      supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
    }
  }
}

监控support.v4.app.Fragment:AndroidSupportFragmentDestroyWatcher类中

同android Fragment的监听一样,在onFragmentViewDestroyed检测View,在onFragmentDestroyed检测Fragment。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X4v1d9JL-1594300470727)(C:\Users\11070535\AppData\Roaming\Typora\typora-user-images\1591758151988.png)]

经过上面对源码的跟进,想必大家应该理解了上面这段话,上述的源码,刚好已经实现了对这些内容的监控

2.3、监控原理

从上面对Activity和fragment 的监控情况来看,所有的内存泄露的监控,最终都调用到了ObjectWatcher对象的watch方法,该方法,才是实现监控内存泄露的核心方法,接下来,让我们一起看下ObjectWatcher的核心实现


class ObjectWatcher constructor(
  private val clock: Clock,
  private val checkRetainedExecutor: Executor,
  /**
   * References passed to [watch].
   * 正在被观察的对象,此时还未泄漏
   */
  private val watchedObjects = mutableMapOf<String, KeyedWeakReference>()
  //引用队列 配合弱引用 定位泄漏的对象。
  private val queue = ReferenceQueue<Any>()
    //泄漏监听
  private val onObjectRetainedListeners = mutableSetOf<OnObjectRetainedListener>()


  /**
   * Watches the provided [watchedObject].
   *
   * @param description Describes why the object is watched.
   */
  @Synchronized fun watch(
    watchedObject: Any,
    description: String
  ) {
    if (!isEnabled()) {
      return
    }
      
    //清除watchedObjects中不存在泄露的弱引用对象  
    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"
    }

    //将本次watch的对象加入到watchedObjects 的map中
    watchedObjects[key] = reference
      
    //通过checkRetainedExecutor,5秒后执行moveToRetained
    checkRetainedExecutor.execute {
      //若依旧存在引用,则通知onObjectRetainedListeners
      moveToRetained(key)
    }
  }

  
 
  @Synchronized private fun moveToRetained(key: String) {
      //清除无需观察的对象
    removeWeaklyReachableObjects()
     //通过key 去找引用,若存在引用,这证明5后,本该回收的对象未能回收,可能存在内存泄露
    val retainedRef = watchedObjects[key]
    if (retainedRef != null) {
      retainedRef.retainedUptimeMillis = clock.uptimeMillis()
      onObjectRetainedListeners.forEach { it.onObjectRetained() }
    }
  }

   
  private fun removeWeaklyReachableObjects() {
    // WeakReferences are enqueued as soon as the object to which they point to becomes weakly
    // reachable. This is before finalization or garbage collection has actually happened.
      
    //queue是一个 ReferenceQueue队列,当一个对象被GC掉之后,会被加入到这个队列当中,即queue中存在的对象,都可以认为是不会存在内存泄露的对象
    var ref: KeyedWeakReference?
    do {
      ref = queue.poll() as KeyedWeakReference?
      if (ref != null) {
        watchedObjects.remove(ref.key)
      }
    } while (ref != null)
  }
}

**知识点:**WeakReference创建时,可以传入一个ReferenceQueue对象,假如WeakReference中引用对象被回收,那么就会把WeakReference对象添加到ReferenceQueue中,可以通过ReferenceQueue中是否为空来判断,被引用对象是否被回收

步骤:

1.向watchedObjects添加需要watch的对象

2.removeWeaklyReachableObjects方法使用WeakReference+ReferenceQueue的原理,不断的从watchedObjects 的map 中删除已经被释放,不会存在内存泄露的对象

3.checkRetainedExecutor 五秒后执行 moveToRetained方法

4.moveToRetained方法则在一直寻找依旧存在与watchedObjects 中的对象,存在,即代表有内存泄露

5.通知泄露

//InternalAppWatcher类中,checkRetainedExecutor的实现方式如下5s后执行
/**
 * How long to wait before reporting a watched object as retained.
 *
 * Default to 5 seconds.
 */
val watchDurationMillis: Long = TimeUnit.SECONDS.toMillis(5)
  private val checkRetainedExecutor = Executor {
    mainHandler.postDelayed(it, AppWatcher.config.watchDurationMillis)
  }
  val objectWatcher = ObjectWatcher(
      clock = clock,
      checkRetainedExecutor = checkRetainedExecutor,
      isEnabled = { AppWatcher.config.enabled }
  )



//InternalLeakCanary类中实现onObjectRetainedListeners的回调
override fun onObjectRetained() {
  if (this::heapDumpTrigger.isInitialized) {
    //后续的堆栈打印相关事宜
    heapDumpTrigger.onObjectRetained()
  }
}



通过上面的流程,想必,大家对这个方法的应用,也有了一定的理解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aigm1XxH-1594300470733)(C:\Users\11070535\AppData\Roaming\Typora\typora-user-images\1591758705567.png)]

三、总结

3.1.它是如何做到仅一行配置代码就完成监控的

​ 1.ContentProvider的onCreate的调用时机是在application onCreate之前调用的,即在应用启动时,完成了自身代码的调用,降低了接入方在java代码层面上的接入成本

​ 2.通过占位符的方式,简化了接入方在manifest文件上的接入成本

​ 3.debugImplementation 仅在debug模式下生效,降低了使用implementation时需要依赖空包的接入成本

3.2 它是在什么时机,去判断是否存在内存泄露的

​ 1.Activity:通过在Application中注册registerActivityLifecycleCallbacks绑定Activity生命周期回调,并在onActivityDestroyed回调中监控Activity

​ 2.Fragment:通过在Application中注册registerActivityLifecycleCallbacks绑定Activity生命周期回调,并在onActivityCreated回调中,通过在Activity中注册注册FragmentLifecycleCallbacks回调,并在onFragmentDestroyed回调时,监控fragment

​ 3.Fragment View:通过在Application中注册registerActivityLifecycleCallbacks绑定Activity生命周期回调,并在onActivityCreated回调中,通过在Activity中注册注册FragmentLifecycleCallbacks回调,并在onFragmentViewDestroyed回调中监控Fragment View

​ 4. ViewModel:针对AndroidX库中的Activity,对于Activit,在onActivityCreated回调中注册监听,对于Fragment,在onFragmentCreated回调中注册监听,,,在ViewModel的onCleared回调中监控ViewModel

3.3 它是通过什么原理,来判断是否存在内存泄露的

​ 是利用了WeakRefrence + RefrenceQueue的机制(仅被弱引用持有的对象,当对象被回收时,会存入到引用队列中),从引用队列中不断的获取对象,将已确认被GC的对象剔除,剩余未被回收的对象则定义为可能泄露的对象,当达到一定的判断条件时,通知用户内存泄露

四、流程图

4.1总流程图

[外链图片转存中…(img-UoXYsJ3v-1594300470734)]

4.2 详细流程图

[外链图片转存中…(img-mxGmkP3S-1594300470735)]

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值