美文网首页
leakcanary shark 库解析 二

leakcanary shark 库解析 二

作者: vb12 | 来源:发表于2023-12-25 13:03 被阅读0次

    1.LeakNodeStatus 三个状态,没用到

    internal enum class LeakNodeStatus {
      NOT_LEAKING,
      LEAKING,
      UNKNOWN;
    }
    

    2.HeapAnalysisException 封装throwable

    class HeapAnalysisException(cause: Throwable) : RuntimeException(cause) {
     
      override fun toString(): String {
        val stringWriter = StringWriter()
        cause!!.printStackTrace(PrintWriter(stringWriter))
        return stringWriter.toString()
      }
     
      companion object {
        private const val serialVersionUID: Long = -2522323377375290608
      }
    }
    

    3.AppSingletonInspector App范围内的单例,标记为不泄漏

    /**
     * Inspector that automatically marks instances of the provided class names as not leaking
     * because they're app wide singletons.
     * 检查器,自动将提供的类名的实例标记为不泄漏,因为它们是应用程序范围的单例。
     *
     */
    class AppSingletonInspector(private vararg val singletonClasses: String) : ObjectInspector {
     
        //检查
        override fun inspect(
                reporter: ObjectReporter//todo ObjectReporter是干哈的
        ) {
            if (reporter.heapObject is HeapInstance) {
                reporter.heapObject.instanceClass
                        .classHierarchy//他自己的类+父类
                        .forEach { heapClass ->
                            if (heapClass.name in singletonClasses) {
                                reporter.notLeakingReasons += "${heapClass.name} is an app singleton"
                            }
                        }
            }
        }
    }
    

    4.MetadataExtractor 元数据提取器接口

    /**
     * Extracts metadata from a hprof to be reported in [HeapAnalysisSuccess.metadata].
     *
     * This is a functional interface with which you can create a [MetadataExtractor] from a lambda.
     * 从 [HeapAnalysisSuccess.metadata] 分析成功的 hprof 中提取元数据。
     * 这是一个功能接口,您可以使用它从 lambda 创建 [MetadataExtractor]。
     */
    fun interface MetadataExtractor {
      fun extractMetadata(graph: HeapGraph): Map<String, String>
     
      companion object {
     
        /**
         * A no-op [MetadataExtractor]
         */
        val NO_OP = MetadataExtractor { emptyMap() }
     
        /**
         * Utility function to create a [MetadataExtractor] from the passed in [block] lambda instead of
         * using the anonymous `object : MetadataExtractor` syntax.
         *
         * Usage:
         *
         * ```kotlin
         * val inspector = MetadataExtractor { graph ->
         *
         * }
         * ```
         */
        inline operator fun invoke(crossinline block: (HeapGraph) -> Map<String, String>): MetadataExtractor =
          object : MetadataExtractor {
            override fun extractMetadata(graph: HeapGraph): Map<String, String> = block(graph)
          }
      }
    }
    

    5.LeakingObjectFinder查找泄漏的对象id们

    /**
     * Finds the objects that are leaking, for which Shark will compute
     * leak traces.
     *
     * This is a functional interface with which you can create a [LeakingObjectFinder] from a lambda.
     * 查找泄漏的对象,Shark 将为其计算泄漏跟踪。 
     * 这是一个函数式接口,您可以使用它从 lambda 创建 [LeakingObjectFinder]。
     */
    fun interface LeakingObjectFinder {
     
      /**
       * For a given heap graph, returns a set of object ids for the objects that are leaking.
       * 对于给定的堆图,返回一组泄漏对象的对象 ID。
       */
      fun findLeakingObjectIds(graph: HeapGraph): Set<Long>
     
      companion object {
        /**
         * Utility function to create a [LeakingObjectFinder] from the passed in [block] lambda
         * instead of using the anonymous `object : LeakingObjectFinder` syntax.
         *
         * Usage:
         *
         * ```kotlin
         * val listener = LeakingObjectFinder {
         *
         * }
         * ```
         */
        inline operator fun invoke(crossinline block: (HeapGraph) -> Set<Long>): LeakingObjectFinder =
          object : LeakingObjectFinder {
            override fun findLeakingObjectIds(graph: HeapGraph): Set<Long> = block(graph)
          }
      }
    }
    

    6.FilteringLeakingObjectFinder通过扫描堆转储中的所有对象并将决策委托给[FilteringLeakingObjectFinder.LeakingObjectFilter]列表来查找泄漏的对象

    /**
     * Finds the objects that are leaking by scanning all objects in the heap dump
     * and delegating the decision to a list of [FilteringLeakingObjectFinder.LeakingObjectFilter]
     * 通过扫描堆转储中的所有对象并将决策委托给[FilteringLeakingObjectFinder.LeakingObjectFilter]列表来查找泄漏的对象
     */
    class FilteringLeakingObjectFinder(private val filters: List<LeakingObjectFilter>) :
      LeakingObjectFinder {
     
      /**
       * Filter to be passed to the [FilteringLeakingObjectFinder] constructor.
       * 要传递给[FilteringLeakingObjectFinder]构造函数的筛选器。
       */
      interface LeakingObjectFilter {
        /**
         * Returns whether the passed in [heapObject] is leaking. This should only return true
         * when we're 100% sure the passed in [heapObject] should not be in memory anymore.
         * 返回传入的[heapObject]是否泄漏。只有当我们100%确定传入的[heapObject]不应再在内存中时,才会返回true。
         */
        fun isLeakingObject(heapObject: HeapObject): Boolean
      }
     
      override fun findLeakingObjectIds(graph: HeapGraph): Set<Long> {
        return graph.objects
          .filter { heapObject ->
            filters.any { filter ->//any表示至少有一个
              filter.isLeakingObject(heapObject)
            }
          }
          .map { it.objectId }
          .toSet()
      }
    }
    

    7.ObjectInspector 对象检查员为 LeakCanary 提供 堆中对象(类、实例和数组)更多的信息。

    package shark
     
    /**
     * Provides LeakCanary with insights about objects (classes, instances and arrays) found in the
     * heap. [inspect] will be called for each object that LeakCanary wants to know more about.
     * The implementation can then use the provided [ObjectReporter] to provide insights for that
     * object.
     *
     * 对象检查员 为 LeakCanary 提供 堆中对象(类、实例和数组)更多的信息。
     * LeakCanary可以调用[inspect]方法,了解对象更多的信息。
     * 实现类可以使用提供的 [ObjectReporter] 来提供该对象的信息。
     *
     * This is a functional interface with which you can create a [ObjectInspector] from a lambda.
     */
    fun interface ObjectInspector {
     
      /**
       * @see [ObjectInspector]
       */
      fun inspect(reporter: ObjectReporter)// ObjectReporter里边保存着label,leakingReasons,notLeakingReasons
     
      companion object {
        /**
         * Utility function to create a [ObjectInspector] from the passed in [block] lambda instead of
         * using the anonymous `object : OnHeapAnalyzedListener` syntax.
         *
         * Usage:
         *
         * ```kotlin
         * val inspector = ObjectInspector { reporter ->
         *
         * }
         * ```
         */
        inline operator fun invoke(crossinline block: (ObjectReporter) -> Unit): ObjectInspector =
          object : ObjectInspector {
            override fun inspect(
              reporter: ObjectReporter
            ) {
              block(reporter)
            }
          }
      }
    }
    

    8.OnAnalysisProgressListener将 [HeapAnalyzer] 的进度报告为 [Step] 值。

    /**
     * Reports progress from the [HeapAnalyzer] as they occur, as [Step] values.
     * 将 [HeapAnalyzer] 的进度报告为 [Step] 值。
     *
     * This is a functional interface with which you can create a [OnAnalysisProgressListener] from a lambda.
     */
    fun interface OnAnalysisProgressListener {
     
      // These steps are defined in the order in which they occur.
      //这些步骤按它们发生的顺序定义。
      enum class Step {
        PARSING_HEAP_DUMP,        //解析dump
        EXTRACTING_METADATA,      //提取metadata
        FINDING_RETAINED_OBJECTS, //retained 保留
        FINDING_PATHS_TO_RETAINED_OBJECTS,//寻找路径到保留对象
        FINDING_DOMINATORS,               //寻找统治者
        INSPECTING_OBJECTS,               //检查对象
        COMPUTING_NATIVE_RETAINED_SIZE,   //计算原生保留大小
        COMPUTING_RETAINED_SIZE,//计算保留大小
        BUILDING_LEAK_TRACES,   //建立泄漏痕迹
        REPORTING_HEAP_ANALYSIS //报告堆分析
      }
     
      fun onAnalysisProgress(step: Step)
     
      companion object {
     
        /**
         * A no-op [OnAnalysisProgressListener]
         */
        val NO_OP = OnAnalysisProgressListener {}
     
        /**
         * Utility function to create a [OnAnalysisProgressListener] from the passed in [block] lambda
         * instead of using the anonymous `object : OnAnalysisProgressListener` syntax.
         *
         * Usage:
         *
         * ```kotlin
         * val listener = OnAnalysisProgressListener {
         *
         * }
         * ```
         */
        inline operator fun invoke(crossinline block: (Step) -> Unit): OnAnalysisProgressListener =
          object : OnAnalysisProgressListener {
            override fun onAnalysisProgress(step: Step) {
              block(step)
            }
          }
      }
    }
    

    9.LeakTraceReference封装LeakTraceObject

    /**
     * A [LeakTraceReference] represents and origin [LeakTraceObject] and either a reference from that
     * object to the [LeakTraceObject] in the next [LeakTraceReference] in [LeakTrace.referencePath],
     * or to [LeakTrace.leakingObject] if this is the last [LeakTraceReference] in
     * [LeakTrace.referencePath].
     *
     * [LeakTraceReference] 封装LeakTraceObject
     */
    data class LeakTraceReference(
      val originObject: LeakTraceObject,
     
      val referenceType: ReferenceType,
     
      val owningClassName: String,
     
      val referenceName: String
     
    ) : Serializable {
     
      enum class ReferenceType {
        INSTANCE_FIELD,
        STATIC_FIELD,
        LOCAL,
        ARRAY_ENTRY
      }
     
      /**
       * Returns {@link #className} without the package, ie stripped of any string content before the
       * last period (included).
       */
      val owningClassSimpleName: String get() = owningClassName.lastSegment('.')
     
      val referenceDisplayName: String
        get() {
          return when (referenceType) {
            ARRAY_ENTRY -> "[$referenceName]"
            STATIC_FIELD, INSTANCE_FIELD -> referenceName
            LOCAL -> "<Java Local>"
          }
        }
     
      val referenceGenericName: String//Generic通用的
        get() {
          return when (referenceType) {
            // The specific array index in a leak rarely matters, this improves grouping.
            ARRAY_ENTRY -> "[x]"
            STATIC_FIELD, INSTANCE_FIELD -> referenceName
            LOCAL -> "<Java Local>"
          }
        }
     
      companion object {
        private const val serialVersionUID = 1L
      }
    }
    

    10.ObjectReporter为ObjectInspector对象检查员提供heapObject相关的信息 , 一个给定的 [ObjectReporter] 只映射到堆中的一个对象,但被许多 [ObjectInspector] 实现共享并积累洞察力。

    /**
     * Enables [ObjectInspector] implementations to provide insights on [heapObject], which is
     * an object (class, instance or array) found in the heap.
     *
     * A given [ObjectReporter] only maps to one object in the heap, but is shared to many
     * [ObjectInspector] implementations and accumulates insights.
     *
     * 为ObjectInspector对象检查员提供heapObject相关的信息
     * 一个给定的 [ObjectReporter] 只映射到堆中的一个对象,但被许多 [ObjectInspector] 实现共享并积累洞察力。
     */
    class ObjectReporter constructor(val heapObject: HeapObject) {
     
      /**
       * Labels that will be visible on the corresponding [heapObject] in the leak trace.
       * 在泄漏跟踪中相应的 [heapObject] 上可见的标签
       */
      val labels = linkedSetOf<String>()
     
      /**
       * Reasons for which this object is expected to be unreachable (ie it's leaking).
       * 预期此对象无法访问的原因(即它正在泄漏)。
       */
      val leakingReasons = mutableSetOf<String>()
     
      /**
       * Deprecated, use leakingReasons instead.
       */
      @Deprecated(
        "Replace likelyLeakingReasons with leakingReasons",
        replaceWith = ReplaceWith(
          "leakingReasons"
        )
      )
      val likelyLeakingReasons
        get() = leakingReasons
     
      /**
       * Reasons for which this object is expected to be reachable (ie it's not leaking).
       * 预期此对象可达的原因(即它没有泄漏)。
       */
      val notLeakingReasons = mutableSetOf<String>()
     
      /**
       * Runs [block] if [ObjectReporter.heapObject] is an instance of [expectedClass].
       * 如果 [ObjectReporter.heapObject] 是 [expectedClass] 的实例,则运行 [block]。
       */
      fun whenInstanceOf(
        expectedClass: KClass<out Any>,
        block: ObjectReporter.(HeapInstance) -> Unit
      ) {
        whenInstanceOf(expectedClass.java.name, block)
      }
     
      /**
       * Runs [block] if [ObjectReporter.heapObject] is an instance of [expectedClassName].
       * 如果 [ObjectReporter.heapObject] 是 [expectedClass] 的实例,则运行 [block]。
       */
      fun whenInstanceOf(
        expectedClassName: String,
        block: ObjectReporter.(HeapInstance) -> Unit
      ) {
        val heapObject = heapObject
        if (heapObject is HeapInstance && heapObject instanceOf expectedClassName) {
          block(heapObject)
        }
      }
    }
    

    11.ReferenceMatcher用于模式匹配堆中已知的引用模式,要么忽略它们([IgnoredReferenceMatcher]), 要么将它们标记为库泄漏([LibraryLeakReferenceMatcher])。

    /**
     * Used to pattern match known patterns of references in the heap, either to ignore them
     * ([IgnoredReferenceMatcher]) or to mark them as library leaks ([LibraryLeakReferenceMatcher]).
     * 用于模式匹配堆中已知的引用模式,要么忽略它们([IgnoredReferenceMatcher]),
     * 要么将它们标记为库泄漏([LibraryLeakReferenceMatcher])。
     */
    sealed class ReferenceMatcher {
     
      /** The pattern that references will be matched against.
       * 引用将匹配的模式 */
      abstract val pattern: ReferencePattern
    }
     
    /**
     * [LibraryLeakReferenceMatcher] should be used to match references in library code that are
     * known to create leaks and are beyond your control. The shortest path finder will only go
     * through matching references after it has exhausted references that don't match, prioritizing
     * finding an application leak over a known library leak. Library leaks will be reported as
     * [LibraryLeak] instead of [ApplicationLeak].
     * [LibraryLeakReferenceMatcher] 应该用于匹配库代码中已知会造成泄漏并且超出您控制范围的引用。
     * 最短路径查找器只会在耗尽不匹配的引用后才通过匹配的引用,优先查找应用程序泄漏而不是已知库泄漏。
     * 库泄漏将报告为 [LibraryLeak] 而不是 [ApplicationLeak]。
     */
    data class LibraryLeakReferenceMatcher(
      override val pattern: ReferencePattern,
      /**
       * A description that conveys what we know about this library leak.
       */
      val description: String = "",
      /**
       * Whether the identified leak may exist in the provided [HeapGraph]. Defaults to true. If
       * the heap dump comes from a VM that runs a different version of the library that doesn't
       * have the leak, then this should return false.
       * 不同虚拟机可能不用,如果一个虚拟机不可能出现这个问题,则返回false
       */
      val patternApplies: (HeapGraph) -> Boolean = { true }
    ) : ReferenceMatcher() {
      override fun toString() = "library leak: $pattern"
    }
     
    /**
     * [IgnoredReferenceMatcher] should be used to match references that cannot ever create leaks. The
     * shortest path finder will never go through matching references.
     * [IgnoredReferenceMatcher] 应该用于匹配永远不会造成泄漏的引用。
     * 最短路径查找器永远不会通过匹配的引用。
     */
    class IgnoredReferenceMatcher(override val pattern: ReferencePattern) : ReferenceMatcher() {
      override fun toString() = "ignored ref: $pattern"
    }
    

    12.KeyedWeakReferenceFinder查找所有的KeyedWeakReference对应的id

    /**
     * Finds all objects tracked by a KeyedWeakReference, ie all objects that were passed to
     * ObjectWatcher.watch.
     * 查找所有的KeyedWeakReference对应的id
     */
    object KeyedWeakReferenceFinder : LeakingObjectFinder {
     
      override fun findLeakingObjectIds(graph: HeapGraph): Set<Long> =
        findKeyedWeakReferences(graph)
          .filter { it.hasReferent && it.isRetained }
                //hasReferent对象存在,并且保留了一段时间
                //isRetained保持; 持有; 保留; 继续拥有;
          .map { it.referent.value }
          .toSet()
     
      //获取heap dump的时间
      fun heapDumpUptimeMillis(graph: HeapGraph): Long? {
        return graph.context.getOrPut("heapDumpUptimeMillis") {
          val keyedWeakReferenceClass = graph.findClassByName("leakcanary.KeyedWeakReference")
          val heapDumpUptimeMillis = if (keyedWeakReferenceClass == null) {
            null
          } else {
            keyedWeakReferenceClass["heapDumpUptimeMillis"]?.value?.asLong
          }
          if (heapDumpUptimeMillis == null) {
            SharkLog.d {
              "leakcanary.KeyedWeakReference.heapDumpUptimeMillis field not found"
            }
          }
          heapDumpUptimeMillis
        }
      }
     
      internal fun findKeyedWeakReferences(graph: HeapGraph): List<KeyedWeakReferenceMirror> {
        return graph.context.getOrPut(KEYED_WEAK_REFERENCE.name) {//todo 这里为什么getOrPut
          val keyedWeakReferenceClass = graph.findClassByName("leakcanary.KeyedWeakReference")
     
          val keyedWeakReferenceClassId = keyedWeakReferenceClass?.objectId ?: 0
          val legacyKeyedWeakReferenceClassId =
            graph.findClassByName("com.squareup.leakcanary.KeyedWeakReference")?.objectId ?: 0
     
          val heapDumpUptimeMillis = heapDumpUptimeMillis(graph)
     
          val addedToContext: List<KeyedWeakReferenceMirror> = graph.instances
            .filter { instance ->
              //过滤所有的instance,找到leakcanary.KeyedWeakReference或者com.squareup.leakcanary.KeyedWeakReference的对象实例
              instance.instanceClassId == keyedWeakReferenceClassId || instance.instanceClassId == legacyKeyedWeakReferenceClassId
            }
            .map {
              //封装为KeyedWeakReferenceMirror
              KeyedWeakReferenceMirror.fromInstance(
                it, heapDumpUptimeMillis
              )
            }
            .toList()
          graph.context[KEYED_WEAK_REFERENCE.name] = addedToContext
          addedToContext
        }
      }
    }
    

    13.ReferencePattern将匹配给定 [ReferenceMatcher] 的引用的模式

    /**
     * A pattern that will match references for a given [ReferenceMatcher].
     * 将匹配给定 [ReferenceMatcher] 的引用的模式。
     */
    sealed class ReferencePattern : Serializable {
     
      /**
       * Matches local references held in the stack of frames of a given thread, identified by its name.
       * 匹配保存在给定线程的帧堆栈中的本地引用,由其名称标识。
       */
      data class JavaLocalPattern(
        val threadName: String
      ) : ReferencePattern() {
        override fun toString() = "local variable on thread $threadName"
     
        companion object {
          private const val serialVersionUID: Long = -8985446122829543654
        }
      }
     
      /**
       * Matches static field references, identified by [className] and [fieldName].
       * 匹配由 [className] 和 [fieldName] 标识的静态字段引用。
       */
      data class StaticFieldPattern(
        val className: String,
        val fieldName: String
      ) : ReferencePattern() {
        override fun toString() = "static field $className#$fieldName"
     
        companion object {
          private const val serialVersionUID: Long = 7656908128775899611
        }
      }
     
      /**
       * Matches instances field references, identified by [className] and [fieldName].
       * 匹配实例字段引用,由 [className] 和 [fieldName] 标识。
       *
       * Note: If [fieldName] is declared in a superclass it will still match for subclasses.
       * This is to support overriding of rules for specific cases. If two [ReferenceMatcher] match for
       * the same [fieldName] but for different [className] in a class hierarchy, then the closest
       * class in the hierarchy wins.
       * 注意:如果 [fieldName] 在超类中声明,它仍然会匹配子类。
       * 这是为了支持在特定情况下覆盖规则。 如果两个 [ReferenceMatcher] 匹配同一个 [fieldName]
       * 但对于类层次结构中的不同 [className],则层次结构中最接近的类获胜。
       */
      data class InstanceFieldPattern(
        val className: String,
        val fieldName: String
      ) : ReferencePattern() {
        override fun toString() = "instance field $className#$fieldName"
     
        companion object {
          private const val serialVersionUID: Long = 6649791455204159802
        }
      }
     
      /**
       * Matches native global variables (also known as jni global gc roots) that reference
       * Java objects. The class name will match against classes, instances and object arrays with
       * a matching class name.
       * 匹配引用 Java 对象的本地全局变量(也称为 jni 全局 gc 根)。
       * 类名将与具有匹配类名的类、实例和对象数组相匹配。
       * todo ??
       */
      data class NativeGlobalVariablePattern(val className: String) : ReferencePattern() {
        override fun toString() = "native global variable referencing $className"
     
        companion object {
          private const val serialVersionUID: Long = -2651328076202244933
        }
      }
     
      companion object {
        private const val serialVersionUID: Long = -5113635523713591133
      }
    }
    

    14.LeakTraceObject 代表泄漏的对象

    data class LeakTraceObject(
      val type: ObjectType,
      /**
       * Class name of the object.
       * The class name format is the same as what would be returned by [Class.getName].
       * 对象的类名。类名格式和[Class.getName]返回的一样。
       */
      val className: String,
     
      /**
       * Labels that were computed during analysis. A label provides extra information that helps
       * understand the state of the leak trace object.
       * 在分析期间计算的标签。 标签提供了有助于了解泄漏跟踪对象状态的额外信息。
       */
      val labels: Set<String>,
      val leakingStatus: LeakingStatus,
      val leakingStatusReason: String,
      /**
       * The minimum number of bytes which would be freed if all references to this object were
       * released. Not null only if the retained heap size was computed AND [leakingStatus] is
       * equal to [LeakingStatus.UNKNOWN] or [LeakingStatus.LEAKING].
       * 如果对该对象的所有引用都被释放,则将被释放的最小字节数。
       * 仅当计算保留堆大小且 [leakingStatus] 等于 [LeakingStatus.UNKNOWN] 或 [LeakingStatus.LEAKING] 时才不为 null。
       */
      val retainedHeapByteSize: Int?,
      /**
       * The minimum number of objects which would be unreachable if all references to this object were
       * released. Not null only if the retained heap size was computed AND [leakingStatus] is
       * equal to [LeakingStatus.UNKNOWN] or [LeakingStatus.LEAKING].
       *
       * 如果对该对象的所有引用都被释放,则无法访问的最小对象数。
       * 仅当计算保留堆大小且 [leakingStatus] 等于 [LeakingStatus.UNKNOWN] 或 [LeakingStatus.LEAKING] 时才不为 null。
       */
      val retainedObjectCount: Int?
    ) : Serializable {
     
      /**
       * Returns {@link #className} without the package, ie stripped of any string content before the
       * last period (included).
       */
      val classSimpleName: String get() = className.lastSegment('.')
     
      val typeName
        get() = type.name.toLowerCase(Locale.US)
     
      override fun toString(): String {
        val firstLinePrefix = ""
        val additionalLinesPrefix = "$ZERO_WIDTH_SPACE  "
        return toString(firstLinePrefix, additionalLinesPrefix, true)
      }
     
      internal fun toString(
        firstLinePrefix: String,
        additionalLinesPrefix: String,
        showLeakingStatus: Boolean,
        typeName: String = this.typeName
      ): String {
        val leakStatus = when (leakingStatus) {
          UNKNOWN -> "UNKNOWN"
          NOT_LEAKING -> "NO ($leakingStatusReason)"
          LEAKING -> "YES ($leakingStatusReason)"
        }
     
        var result = ""
        result += "$firstLinePrefix$className $typeName"
        if (showLeakingStatus) {
          result += "\n${additionalLinesPrefix}Leaking: $leakStatus"
        }
     
        if (retainedHeapByteSize != null) {
          val humanReadableRetainedHeapSize =
            humanReadableByteCount(retainedHeapByteSize.toLong())
          result += "\n${additionalLinesPrefix}Retaining $humanReadableRetainedHeapSize in $retainedObjectCount objects"
        }
        for (label in labels) {
          result += "\n${additionalLinesPrefix}$label"
        }
        return result
      }
     
      enum class ObjectType {
        CLASS,
        ARRAY,
        INSTANCE
      }
     
      enum class LeakingStatus {
        /** The object was needed and therefore expected to be reachable.
         * 该对象是需要的,因此预计是可达的。 */
        NOT_LEAKING,
     
        /** The object was no longer needed and therefore expected to be unreachable.
         * 不再需要该对象,因此预计将无法访问该对象。 */
        LEAKING,
     
        /** No decision can be made about the provided object. */
        UNKNOWN;
      }
     
      companion object {
        private const val serialVersionUID = -3616216391305196341L
     
        // https://stackoverflow.com/a/3758880
        //将bytes long型转为可读的B,kB,MB,GB
        private fun humanReadableByteCount(bytes: Long): String {
          val unit = 1000
          if (bytes < unit) return "$bytes B"
          val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
          val pre = "kMGTPE"[exp - 1]
          return String.format("%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
        }
      }
    }
    

    相关文章

      网友评论

          本文标题:leakcanary shark 库解析 二

          本文链接:https://www.haomeiwen.com/subject/gxdkndtx.html