Android LeakCanary的使用方法介绍

 更新时间:2022年09月07日 15:15:10   作者:且听真言  
在Android的性能优化中,内存优化是必不可少的点,而内存优化最重要的一点就是解决内存泄漏的问题,在Android的内存泄漏分析工具也不少,比如PC端的有:AndroidStudio自带的Android Profiler、MAT等工具;手机端也有,就是我们今天要介绍的LeakCanary

1.LeakCanary 如何自动初始化

LeakCanary只需添加依赖就可以实现自动初始化。LeakCanary是通过ContentProvider实现初始化的,在ContentProvider 的 onCreate方法中初始化LeakCanary。并且MainProcessAppWatcherInstaller是在主线程中初始化的。注意:ContentProvider的初始化是在Application的onCreate之前完成的,所以LeakCanary的初始化方法AppWatcher.manualInstall(application)也是在Application的onCreate之前完成的。

internal class MainProcessAppWatcherInstaller : ContentProvider() {
   override fun onCreate(): Boolean {
      val application = context!!.applicationContext as Application
      AppWatcher.manualInstall(application)
      return true
    }
     ... ...
}

2.LeakCanary如何检测内存泄漏

2.1LeakCanary初始化时做了什么

AppWatcher.kt

@JvmOverloads
fun manualInstall(
  application: Application,
  retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
  watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
) {
  checkMainThread()
  if (isInstalled) {
    throw IllegalStateException(
      "AppWatcher already installed, see exception cause for prior install call", installCause
    )
  }
  check(retainedDelayMillis >= 0) {
    "retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
  }
  installCause = RuntimeException("manualInstall() first called here")
  this.retainedDelayMillis = retainedDelayMillis
  if (application.isDebuggableBuild) {
    LogcatSharkLog.install()
  }
  // Requires AppWatcher.objectWatcher to be set
  LeakCanaryDelegate.loadLeakCanary(application)
  watchersToInstall.forEach {
    it.install()
  }
}
fun appDefaultWatchers(
  application: Application,
  reachabilityWatcher: ReachabilityWatcher = objectWatcher
): List<InstallableWatcher> {
  return listOf(
    ActivityWatcher(application, reachabilityWatcher),
    FragmentAndViewModelWatcher(application, reachabilityWatcher),
    RootViewWatcher(reachabilityWatcher),
    ServiceWatcher(reachabilityWatcher)
  )
}

在appDefaultWatchers方法中,会默认初始化一些Watcher,在默认情况下,我们只会监控Activity,Fragment,RootView,Service这些对象是否泄漏。

2.2LeakCanary如何触发检测

以ActivityWatcher为例:

/**
 * Expects activities to become weakly reachable soon after they receive the [Activity.onDestroy]
 * callback.
 */
class ActivityWatcher(
  private val application: Application,
  private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
  private val lifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
      override fun onActivityDestroyed(activity: Activity) {
        reachabilityWatcher.expectWeaklyReachable(
          activity, "${activity::class.java.name} received Activity#onDestroy() callback"
        )
      }
    }
  override fun install() {
    application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
  }
  override fun uninstall() {
    application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
  }
}

在Activity.onDestory时,就会触发检测内存泄漏。通过ActivityLifecycleCallbacks监听生命周期变化,在onActivityDestroyed方法中调用ReachabilityWatcher的expectWeaklyReachable方法。

2.3LeakCanary如何检测泄漏的对象

以Activity为例,通过ReachabilityWatcher的expectWeaklyReachable方法检测。

fun interface ReachabilityWatcher {
  /**
   * Expects the provided [watchedObject] to become weakly reachable soon. If not,
   * [watchedObject] will be considered retained.
   */
  fun expectWeaklyReachable(
    watchedObject: Any,
    description: String
  )
}

ObjectWatcher.kt

ObjectWatcher实现ReachabilityWatcher接口。

private val watchedObjects = mutableMapOf()

private val queue = ReferenceQueue()

@Synchronized override fun expectWeaklyReachable(
  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)
  }
}

1.通过观察的实例watchedObject构建弱引用KeyedWeakReference实例,watchedObject与ReferenceQueue关联,当对象被回收时,该弱引用对象将被存入ReferenceQueue当中。

2.弱引用KeyedWeakReference实例会被被存储在watchedObjects中(Map)。

3.检测过程中,会调用removeWeaklyReachableObjects,将已回收对象从watchedObjects中移除。

4.如果watchedObjects中没有移除对象,证明它没有被回收,那么就会调用moveToRetained。

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.
  var ref: KeyedWeakReference?
  do {
    ref = queue.poll() as KeyedWeakReference?
    if (ref != null) {
      watchedObjects.remove(ref.key)
    }
  } while (ref != null)
}
@Synchronized private fun moveToRetained(key: String) {
  removeWeaklyReachableObjects()
  val retainedRef = watchedObjects[key]
  if (retainedRef != null) {
    retainedRef.retainedUptimeMillis = clock.uptimeMillis()
    onObjectRetainedListeners.forEach { it.onObjectRetained() }
  }
}

2.4弱引用 WeakReference

只要 GC 发现一个对象只有弱引用,则就会回收此弱引用对象。

public class WeakReference<T> extends Reference<T> {
    public WeakReference(T referent) {
        super(referent);
    }
    public WeakReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }
}
var str: Any? = Any()
val quque = ReferenceQueue<Any>()
val weakReference = WeakReference<Any>(str, quque)
val weakReference_before_gc = weakReference.get()
Log.v("reference_tag", weakReference_before_gc.toString())
str = null
System.gc()
Handler().postDelayed( {
    val weakReference_after_gc = weakReference.get()
    Log.v("reference_tag", weakReference_after_gc.toString())
}, 2000)

2022-02-27 17:43:04.181 16634-16634/com.example.myapplication V/reference_tag: java.lang.Object@c87946a
2022-02-27 17:43:06.182 16634-16634/com.example.myapplication V/reference_tag: null

到此这篇关于Android LeakCanary的使用方法介绍的文章就介绍到这了,更多相关Android LeakCanary内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • android 传感器(OnSensorChanged)使用介绍

    android 传感器(OnSensorChanged)使用介绍

    当传感器的值发生变化时,例如磁阻传感器方向改变时会调用OnSensorChanged(). 当传感器的精度发生变化时会调用OnAccuracyChanged()方法
    2014-11-11
  • Android自定义View实现角度选择器

    Android自定义View实现角度选择器

    前几天在Google Photos查看照片,用了一下它的图片剪裁功能,于是我马上就被其界面和操作吸引。后来想模仿做一个和Google Photos裁图页面几乎一模一样的角度选择器,本文比较基础,在阅读本文前只需要掌握最基础的自定义View知识和Android事件知识。下面来一起学习下吧。
    2016-11-11
  • Android开发之模仿微信打开网页的进度条效果(高仿)

    Android开发之模仿微信打开网页的进度条效果(高仿)

    这篇文章主要介绍了Android开发之模仿微信打开网页的进度条效果(高仿)的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-07-07
  • Android应用程序模型之应用程序,任务,进程,线程分析

    Android应用程序模型之应用程序,任务,进程,线程分析

    这篇文章主要介绍了Android应用程序模型之应用程序,任务,进程,线程分析,较为详细的分析了Android应用程序模型中关于任务、进程、线程的相关概念及注意事项,需要的朋友可以参考下
    2016-01-01
  • Android中使用AspectJ详解

    Android中使用AspectJ详解

    本文主要介绍了Android中使用AspectJ的相关知识。具有很好的参考价值。下面跟着小编一起来看下吧
    2017-04-04
  • Android中aapt命令实践

    Android中aapt命令实践

    本篇文章给大家详解了Android aapt命令介绍及常用命令实践,有这方面需求的朋友跟着学习下吧。
    2018-01-01
  • Android WebView 优化之路

    Android WebView 优化之路

    Android WebView 优化之路,如何才能更有效的对Android WebView进行优化,本文将为大家一一举例,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • Android Recyclerview实现左滑删除功能

    Android Recyclerview实现左滑删除功能

    这篇文章主要为大家详细介绍了Android Recyclerview实现左滑删除功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • Android自定义Toolbar使用方法详解

    Android自定义Toolbar使用方法详解

    这篇文章主要为大家详细介绍了Android自定义Toolbar使用方法 ,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • Android apk无法安装及闪退问题解决办法

    Android apk无法安装及闪退问题解决办法

    这篇文章主要介绍了Android apk无法安装及闪退问题的相关资料,这里对闪退问题进行详解及解决步骤的详细介绍,需要的朋友可以参考下
    2017-07-07

最新评论