Android 性能优化之 LeakCanary使用方法

Posted 不入流Android开发

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 性能优化之 LeakCanary使用方法相关的知识,希望对你有一定的参考价值。

背景

android应用中,一个好的产品,除了功能强大,好的性能也是必不可少的。有调查显示,近90%的受访者会因为App卡顿,内存大等问题而卸载该应用,因此手机的性能问题会影响用户的体验,如果用户觉得该应用的体验度不好,会直接卸载或切换其他平台。

对于性能优化,很多大公司会专门招聘性能优化的人员。也有些初级工程师会接触到这部分的工作,但是无从下手,对专业工具和专业代码使用以及分析比较吃力,排查起来也比较费劲。如果有专业的工具能够只管的把这些记录并标记好。这样初级工程师也可以通过详情的问题去排查,那么LeaksCanary就是这款工具了。

LeaksCanary 介绍

LeakCanary是Square公司为Android开发者提供的一个自动检测内存泄漏的工具。

LeakCanary本质上是一个基于MAT进行Android应用程序内存泄漏自动化检测的的开源工具,我们可以通过集成LeakCanary提供的jar包到自己的工程中,一旦检测到内存泄漏,LeakCanary就会dump Memory信息,并通过另一个进程分析内存泄漏的信息并展示出来,随时发现和定位内存泄漏问题,而不用每次在开发流程中都抽出专人来进行内存泄漏问题检测,极大地方便了Android应用程序的开发。

使用方法

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)

到此这篇关于Android LeakCanary的使用方法介绍的文章就介绍到这了,更多相关Android 性能优化相关只是可参考小编分享在下面的文档,访问下方链接获取。

Android性能优化修炼手册:http: //​docs.qq.com/doc/DWGRIR1hVWkFoZWVK

Android 性能优化之 LeakCanary 的使用及项目中的实际运用

文章目录

引言

Andorid项目中我们会使用第三方开源库来检查内存泄露情况,使用时我们得了解其运行原理,并根据反馈日志分析定位问题,并以此解决内存泄露问题。

文本从结合内存泄露原理和在项目中的实际的使用场景来解决开发的实际问题。

1. 什么是内存泄露?

一些对象有着有限的生命周期。当这些对象所要做的事情完成了,我们希望他们会被回收掉。但是如果有一系列对这个对象的引用,那么在我们期待这个对象生命周期结束的时候被收回的时候,它是不会被回收的。它还会占用内存,这就造成了内存泄露。持续累加,内存很快被耗尽。

比如,当 Activity.onDestroy 被调用之后,activity 以及它涉及到的 view 和相关的 bitmap 都应该被回收。但是,如果有一个后台线程持有这个 activity 的引用,那么 activity 对应的内存就不能被回收。这最终将

以上是关于Android 性能优化之 LeakCanary使用方法的主要内容,如果未能解决你的问题,请参考以下文章

Android性能优化之利用LeakCanary检测内存泄漏及解决办法(转)

Android性能优化之利用LeakCanary检测内存泄漏及解决办法(转)

Android性能优化之常见的内存泄漏

OS + Android performance matrix / memory LeakCanary

都2020年了Android开发者,别再忽视LeakCanary了

LeakCanary 内存泄漏 监测 性能优化 简介 原理