栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

leakcanary使用(LeakCanary的原理分析)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

leakcanary使用(LeakCanary的原理分析)

我们先来看看ReferenceQueue的作用

Reference对象所引用的对象被GC回收时,该Reference对象将会被加入与之关联的ReferenceQueue的队列末尾

这里的Reference对象指的是Java的四种引用对象(强引用、软引用、弱引用、虚引用)

如何使用?
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

public class WeakReferenceTest {

    public static void main(String[] args) {

        ReferenceQueue referenceQueue = new ReferenceQueue();

        Object obj = new Object();

        //把obj放入weakReference,并和一个referenceQueue关联
        //当obj被gc回收后,weakReference会被加入referenceQueue队列的末尾
        WeakReference weakReference = new WeakReference(obj,referenceQueue);
        System.out.println("盛放obj的weakReference = " + weakReference);

        //把obj置空,让它没有强引用
        obj = null;

        Runtime.getRuntime().gc();//gc,回收obj

        try{
            Thread.sleep(1000);
        }catch (Exception e){}

        Reference findRef = null;

        while((findRef = referenceQueue.poll()) !=null){
            System.out.println("findRef = " +findRef);
            System.out.println(findRef == weakReference);
            //如果能找到上面的weakReference => 说明它盛放的obj被gc回收了
        }
    }
}
LeakCanary源码分析(leakcanary-2.2)

leakcanary-object-watcher-android模块的AndroidManifest.xml

    

AppWatcherInstaller

  override fun onCreate(): Boolean {
    val application = context!!.applicationContext as Application
    InternalAppWatcher.install(application)
    return true
  }

InternalAppWatcher

  fun install(application: Application) {
    SharkLog.logger = DefaultCanaryLog()
    SharkLog.d { "Installing AppWatcher" }
    //检查当前线程是否是是主线程
    checkMainThread()
    if (this::application.isInitialized) {
      //如果LeakCanary已经加载过,直接返回
      return
    }
    InternalAppWatcher.application = application

    val configProvider = { AppWatcher.config }
    //监视Activity
    ActivityDestroyWatcher.install(application, objectWatcher, configProvider)
    //监视Fragment
    FragmentDestroyWatcher.install(application, objectWatcher, configProvider)
    //调用上层模块InternalLeakCanary.invoke
    onAppWatcherInstalled(application)
  }

下面我们先看监视Activity的代码,ActivityDestroyWatcher

  companion object {
    fun install(
      application: Application,
      objectWatcher: ObjectWatcher,
      configProvider: () -> Config
    ) {
	   //创建activityDestroyWatcher
      val activityDestroyWatcher =
        ActivityDestroyWatcher(objectWatcher, configProvider)
       //与application绑定
      application.registerActivityLifecycleCallbacks(activityDestroyWatcher.lifecycleCallbacks)
    }
  }

ActivityDestroyWatcher

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

ObjectWatcher

  @Synchronized fun watch(
    watchedObject: Any,
    description: String
  ) {
    if (!isEnabled()) {
      return
    }
    //将可回收的activity删除
    removeWeaklyReachableObjects()
    val key = UUID.randomUUID()
        .toString()
    val watchUptimeMillis = clock.uptimeMillis()
    //创建KeyedWeakReference(是WeakReference的子类),绑定ReferenceQueue
    val reference =
      //watchedObject:activity, key:uuid, queue:ReferenceQueue
      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"
    }
	//将reference保存到watchedObjects数组中
    watchedObjects[key] = reference
    //启动延时5s任务
    checkRetainedExecutor.execute {
      moveToRetained(key)
    }
  }
  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)
  }
//延时5s任务
val watchDurationMillis: Long = TimeUnit.SECONDS.toMillis(5)

private val checkRetainedExecutor = Executor {
    mainHandler.postDelayed(it, AppWatcher.config.watchDurationMillis)
}
  @Synchronized private fun moveToRetained(key: String) {
  	//将可达activity删除
    removeWeaklyReachableObjects()
    val retainedRef = watchedObjects[key]
    if (retainedRef != null) {
      //保存当前时间作为内存泄露的时间
      retainedRef.retainedUptimeMillis = clock.uptimeMillis()
      //通知InternalLeakCanary发生内存泄露
      onObjectRetainedListeners.forEach { it.onObjectRetained() }
    }
  }

InternalLeakCanary

  override fun onObjectRetained() {
    if (this::heapDumpTrigger.isInitialized) {
    //通知heapDumpTrigger有内存泄露
      heapDumpTrigger.onObjectRetained()
    }
  }

HeapDumpTrigger

  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 ${scheduledIn}ms" }
      return
    } else {
      val verb = if (rescheduling) "Rescheduling" else "Scheduling"
      val delay = if (delayMillis > 0) " in ${delayMillis}ms" else ""
      SharkLog.d { "$verb check for retained objects${delay} because $reason" }
    }
    checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
    backgroundHandler.postDelayed({
      checkScheduledAt = 0
      //检查泄露对象
      checkRetainedObjects(reason)
    }, delayMillis)
  }
  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) {
    //GC一次,确认所有剩余对象都是内存泄露的对象
      gcTrigger.runGc()
      retainedReferenceCount = objectWatcher.retainedObjectCount
    }
	//检查当前剩余对象的个数
    if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return
	//如果配置了debug不dumpHeap并且正在debug
    if (!config.dumpHeapWhenDebugging && DebuggerControl.isDebuggerAttached) {
      onRetainInstanceListener.onEvent(DebuggerIsAttached)
      showRetainedCountNotification(
          objectCount = retainedReferenceCount,
          contentText = application.getString(
              R.string.leak_canary_notification_retained_debugger_attached
          )
      )
      //延时20s执行
      scheduleRetainedObjectCheck(
          reason = "debugger is attached",
          rescheduling = true,
          delayMillis = WAIT_FOR_DEBUG_MILLIS
      )
      return
    }
    
    val now = SystemClock.uptimeMillis()
    val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis
    //WAIT_BETWEEN_HEAP_DUMPS_MILLIS为60s,60s内执行一次操作
    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 ${elapsedSinceLastDumpMillis}ms ago (< ${WAIT_BETWEEN_HEAP_DUMPS_MILLIS}ms)",
          rescheduling = true,
          delayMillis = WAIT_BETWEEN_HEAP_DUMPS_MILLIS - elapsedSinceLastDumpMillis
      )
      return
    }

    SharkLog.d { "Check for retained objects found $retainedReferenceCount objects, dumping the heap" }
    dismissRetainedCountNotification()
    //执行dumpHeap操作
    dumpHeap(retainedReferenceCount, retry = true)
}
  private fun checkRetainedCount(
    retainedKeysCount: Int,
    retainedVisibleThreshold: Int
  ): Boolean {
    val countChanged = lastDisplayedRetainedObjectCount != retainedKeysCount
    lastDisplayedRetainedObjectCount = retainedKeysCount
    if (retainedKeysCount == 0) {
      SharkLog.d { "Check for retained object found no objects remaining" }
      if (countChanged) {
        onRetainInstanceListener.onEvent(NoMoreObjects)
        showNoMoreRetainedObjectNotification()
      }
      //剩余对象为0
      return true
    }
	//剩余对象低于阈值5个
    if (retainedKeysCount < retainedVisibleThreshold) {
    
      //当前应用可见或不可见时间间隔小于5s
      if (applicationVisible || applicationInvisibleLessThanWatchPeriod) {
        if (countChanged) {
          onRetainInstanceListener.onEvent(BelowThreshold(retainedKeysCount))
        }
        showRetainedCountNotification(
            objectCount = retainedKeysCount,
            contentText = application.getString(
                R.string.leak_canary_notification_retained_visible, retainedVisibleThreshold
            )
        )
        //重新安排2s后执行checkRetainedObejcts
        scheduleRetainedObjectCheck(
            reason = "found only $retainedKeysCount retained objects (< $retainedVisibleThreshold while app visible)",
            rescheduling = true,
            delayMillis = WAIT_FOR_OBJECT_THRESHOLD_MILLIS
        )
        return true
      }
    }
    return false
  }

GcTrigger

  object Default : GcTrigger {
    override fun runGc() {
      // Code taken from AOSP FinalizationTest:
      // https://android.googlesource.com/platform/libcore/+/master/support/src/test/java/libcore/
      // java/lang/ref/FinalizationTester.java
      // System.gc() does not garbage collect every time. Runtime.gc() is
      // more likely to perform a gc.
      // System.gc()并不会每次执行GC,Runtime.gc()会
      Runtime.getRuntime()
          .gc()
      enqueueReferences()
      System.runFinalization()
    }

LeakCanary的缺点
1.自己在分析的时候容易OOM
2.只针对Activity和Fragment进行预设埋点,我们需要自己定制源码,针对对象进行裁剪
3.只分析Retain size大的对象,或者是对内存对象裁剪,不全部加载到内存中

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/773503.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号