main

square/leakcanary

Last updated at: 29/12/2023 09:39

KeyedWeakReferenceMirror.kt

TLDR

This file contains the implementation of the KeyedWeakReferenceMirror class, which represents a mirrored version of a weak reference in the heap dump.

Classes

KeyedWeakReferenceMirror

The KeyedWeakReferenceMirror class represents a mirrored version of a weak reference in the heap dump. It has the following properties:

  • referent - The reference to the object being referred to.
  • key - The key associated with the weak reference.
  • description - The description of the weak reference. (Note: In pre-2.0 heap dumps, this field is named "name").
  • watchDurationMillis - The duration for which the weak reference has been watched. (Note: This field is null in pre-2.0 alpha 3 heap dumps).
  • retainedDurationMillis - The duration for which the referent object has been retained. (Note: This field is null in pre-2.0 alpha 3 heap dumps, and -1 if the instance is not retained).

The KeyedWeakReferenceMirror class also has the following methods:

  • hasReferent - Checks if the weak reference has a referent object.
  • isRetained - Checks if the referent object is retained.

Note: This class is in the shark.internal package.

package shark.internal

import shark.HeapObject.HeapInstance
import shark.ValueHolder
import shark.ValueHolder.ReferenceHolder

internal class KeyedWeakReferenceMirror(
  val referent: ReferenceHolder,
  val key: String,
  // The name field does not exist in pre 1.0 heap dumps.
  val description: String,
  // null in pre 2.0 alpha 3 heap dumps
  val watchDurationMillis: Long?,
  // null in pre 2.0 alpha 3 heap dumps, -1 if the instance is not retained.
  val retainedDurationMillis: Long?
) {

  val hasReferent = referent.value != ValueHolder.NULL_REFERENCE

  val isRetained = retainedDurationMillis == null || retainedDurationMillis != -1L

  companion object {

    private const val UNKNOWN_LEGACY = "Unknown (legacy)"

    fun fromInstance(
      weakRef: HeapInstance,
      // Null for pre 2.0 alpha 3 heap dumps
      heapDumpUptimeMillis: Long?
    ): KeyedWeakReferenceMirror {

      val keyWeakRefClassName = weakRef.instanceClassName
      val watchDurationMillis = if (heapDumpUptimeMillis != null) {
        heapDumpUptimeMillis - weakRef[keyWeakRefClassName, "watchUptimeMillis"]!!.value.asLong!!
      } else {
        null
      }

      val retainedDurationMillis = if (heapDumpUptimeMillis != null) {
        val retainedUptimeMillis =
          weakRef[keyWeakRefClassName, "retainedUptimeMillis"]!!.value.asLong!!
        if (retainedUptimeMillis == -1L) -1L else heapDumpUptimeMillis - retainedUptimeMillis
      } else {
        null
      }

      val keyString = weakRef[keyWeakRefClassName, "key"]!!.value.readAsJavaString()!!

      // Changed from name to description after 2.0
      val description = (weakRef[keyWeakRefClassName, "description"]
        ?: weakRef[keyWeakRefClassName, "name"])?.value?.readAsJavaString() ?: UNKNOWN_LEGACY
      return KeyedWeakReferenceMirror(
        watchDurationMillis = watchDurationMillis,
        retainedDurationMillis = retainedDurationMillis,
        referent = weakRef["java.lang.ref.Reference", "referent"]!!.value.holder as ReferenceHolder,
        key = keyString,
        description = description
      )
    }
  }
}