leakcanary是如何捕获内存泄漏的


Java中第三方应用如果想判断是否存在内存泄漏,一般都会利用WeakReference + RefercenceQueue的机制去判定.

因为GC之后,理论上会回收掉WeakRefercence对象的内存(如果不存在其他到GCRoot的路径的话),因此如果GC之后,对象真的被回收了,则不存在内存泄漏,对象没有被回收,则可能存在内存泄漏.

来看一下leakcanary中的判定逻辑吧:

  @Synchronized fun watch(
    watchedObject: Any,
    description: String
  ) {
    if (!isEnabled()) {
      return
    }
    // 清除之前可以访问到的对象
    removeWeaklyReachableObjects()

    val key = UUID.randomUUID()
        .toString()
    val watchUptimeMillis = clock.uptimeMillis()

    // 使用WeakReference + ReferenceQueue
    val reference =
      KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
    watchedObjects[key] = reference

    // 5s之后进行GC
    checkRetainedExecutor.execute {
      moveToRetained(key)
    }
  }

  private fun removeWeaklyReachableObjects() {
    var ref: KeyedWeakReference?
    do {
      ref = queue.poll() as KeyedWeakReference?
      if (ref != null) {
        watchedObjects.remove(ref.key)
      }
    } while (ref != null)
  }

判断的是否存在内存泄漏的基本流程如下:

  1. 在对应生命周期回调之后,拿到要监控的对象,比如Activity/Fragment/View/ViewModel等

  2. 使用WeakReference + ReferenceQueue封装对象

    GC之后会回收WeakReference中没有被强引用的对象内存,因此可以用WeakReference来判断是否存在内存泄漏

  3. 5s后强制进行GC,GC前后都会判断当前保存的对象数,进行对比,如果GC后对象依然没有被回收,则判断该对象可能存在内存泄漏

          Runtime.getRuntime()
              .gc()
          enqueueReferences()
          System.runFinalization()

    这里的enqueueRefercences()其实就是让后台线程sleep 100ms,等待GC处理引用队列完毕.

    System.gc() : 并不一定每次都会执行GC

    Runtime.gc() : 比System.gc()更可能去执行GC

  4. 判断时间间隔是否小于1min,如果大于1min则dump HPROF文件:

     Debug.dumpHprofData(heapDumpFile.absolutePath)
  5. 使用leakcanary 中的 shark 库去分析HPROF文件

    不再是使用的haha库了


文章作者: 姜康
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 姜康 !
评论
 上一篇
GC与Reference GC与Reference
引用类型 SoftReference 普通的GC不会回收软引用,只有在即将发生OOM的时候(即最后一次Full GC),如果被引用的对象只有SoftReference指向的引用,才会被回收. WeakReference 当发生GC时,如果
2020-11-02
下一篇 
leakcanary捕获内存泄漏的时机 leakcanary捕获内存泄漏的时机
leakcannary可以自动监控的内存泄漏有哪些? destroyed Activity对象 destroyed Fragment对象 destroyed fragment中的View对象 cleared ViewModel对象 (Act
2020-10-29
  目录