LeakCanary 源码详解(2)

如果你是直接这篇文章进来的,可以从上篇看起,不是可以是必须:上一篇 LeakCanary源码详解(1)
接着上一篇说的源码部分,分析一下这图中核心代码的意思:注释了里面的逻辑在下图,
LeakCanary 源码详解(2)_第1张图片
注意上图的checkRetainedExecutor 会在5s后再调用,设定是在下图库初始化的时候设定的。
LeakCanary 源码详解(2)_第2张图片

里面有一个 removeWeaklyReachableObjects,这个函数的字面意思 移除弱引用可达的对象,看下图这个函数里面的逻辑,queue就是ReferenceQueue队列,watchedObjects,这个就是个mutableMapOf,其中的值KeyedWeakReference是由上个图上的 KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)来构造的,把我们要检查的对象(强引用的)加入弱引用中,这个queue作为参数传进去了,在声明一个 WeakReference 对象时如果同时传入了 ReferenceQueue 作为构造参数的话,那么当 WeakReference 持有的对象被 GC 回收时,JVM 就会把这个弱引用存入与之关联的引用队列之中。依靠这个特性,我们就可以实现内存泄露的检测了,你理解了这个之后再看上图和下图中的注释就好理解了:removeWeaklyReachableObjects, 根据queue poll出队列,如果里面是空的,说明弱引用里面的强引用对象没有gc回收掉,那么watchedObjects里面对应的这个弱引用就不会被remove,那么就会还存在,在watcheObjects根据key取这个弱引用就不为空,说明泄漏了,开始回调listener
LeakCanary 源码详解(2)_第3张图片

moveToRetained方法
LeakCanary 源码详解(2)_第4张图片然后是onObjectRetained方法
LeakCanary 源码详解(2)_第5张图片
它其实是在下图的代码中这里添加的

LeakCanary 源码详解(2)_第6张图片这个方法又指向了scheduleRetainedObjectCheck,你也看到了接着调用了heapDumpTrigger.scheduleRetainedObjectCheck()
LeakCanary 源码详解(2)_第7张图片,我们看看 heapDumpTrigger.scheduleRetainedObjectCheck(),看看断点的方法 checkRetainedObjects()
LeakCanary 源码详解(2)_第8张图片重点3个,第一处是手动调用了gc(怕前面即使有5s的时间,也没有进行gc),第二处,再次检查残留的object,第三处如果还有残留的,要通知用户,就是报内存泄露提醒
LeakCanary 源码详解(2)_第9张图片我们看看第三处的细节重点就是 这个PendingIntent,使用 FLAG_IMMUTABLE 标记构建了无法被修改的 PendingIntent。

调用 NotificationManagerCompat.notify() 之后工作就完成了。当系统显示通知,且用户点击通知时,会在我们的 PendingIntent 上调用 PendingIntent.send(),来启动我们的应用的广播,这个时候才会去heap dump ,这有点懒加载到意思吧,哈哈。都是细节。

LeakCanary 源码详解(2)_第10张图片(sample 中 点击 recreate 按钮的 有一个 checkRetainedObjects scheduleRetainedObjectCheck checkRetainedObjects 循环,不清楚什么用意)

下面图中,我们可以看到在我们点击通知后,看到代码做了什么动作
LeakCanary 源码详解(2)_第11张图片LeakCanary 源码详解(2)_第12张图片

 fun onDumpHeapReceived(forceDump: Boolean) {
    backgroundHandler.post {
      dismissNoRetainedOnTapNotification()
      gcTrigger.runGc()
      val retainedReferenceCount = objectWatcher.retainedObjectCount
      if (!forceDump && retainedReferenceCount == 0) {
        SharkLog.d { "Ignoring user request to dump heap: no retained objects remaining after GC" }
        @Suppress("DEPRECATION")
        val builder = Notification.Builder(application)
          .setContentTitle(
            application.getString(R.string.leak_canary_notification_no_retained_object_title)
          )
          .setContentText(
            application.getString(
              R.string.leak_canary_notification_no_retained_object_content
            )
          )
          .setAutoCancel(true)
          .setContentIntent(NotificationReceiver.pendingIntent(application, CANCEL_NOTIFICATION))
        val notification =
          Notifications.buildNotification(application, builder, LEAKCANARY_LOW)
        notificationManager.notify(
          R.id.leak_canary_notification_no_retained_object_on_tap, notification
        )
        backgroundHandler.postDelayed(
          scheduleDismissNoRetainedOnTapNotification,
          DISMISS_NO_RETAINED_OBJECT_NOTIFICATION_MILLIS
        )
        lastDisplayedRetainedObjectCount = 0
        return@post
      }

      SharkLog.d { "Dumping the heap because user requested it" }
      dumpHeap(retainedReferenceCount, retry = false, "user request")
    }

重点在最后一行 dumpheap 真正开始收集hprof文件了。

Heap Dump也叫堆转储文件,是一个Java进程在某个时间点上的内存快照。Heap Dump是有着多种类型的。不过总体上heap dump在触发快照的时候都保存了java对象和类的信息。通常在写heap dump文件前会触发一次FullGC,所以heap dump文件中保存的是FullGC后留下的对象信息。
LeakCanary 源码详解(2)_第13张图片最后我们找到真正做事的是Debug去取的hprof文件。
LeakCanary 源码详解(2)_第14张图片
未完,待续。。。
下一篇:LeakCanary 源码详解(3)

你可能感兴趣的:(源码解析,java,android,开发语言)