KeyedWeakReferenceFinder.kt
TLDR
This file defines an object called KeyedWeakReferenceFinder
that implements the LeakingObjectFinder
interface. It contains a method called findLeakingObjectIds
which finds all objects tracked by a KeyedWeakReference
and returns their IDs. It also includes a method called heapDumpUptimeMillis
which retrieves the uptime in milliseconds when the heap dump was taken. Additionally, there is an internal method called findKeyedWeakReferences
which finds all instances of KeyedWeakReferenceMirror
in the heap graph.
Methods
findLeakingObjectIds
This method finds all objects in the heap graph that are tracked by a KeyedWeakReference
. It filters the KeyedWeakReference
instances to select those that have a non-null referent and are retained. It then maps these instances to their values and returns a set of the resulting object IDs.
heapDumpUptimeMillis
This method retrieves the uptime in milliseconds when the heap dump was taken. It checks if the leakcanary.KeyedWeakReference.heapDumpUptimeMillis
field exists in the heap graph. If it does, the value of this field is returned. Otherwise, null
is returned. If the field is not found, a log message is printed.
findKeyedWeakReferences
This internal method finds and returns a list of KeyedWeakReferenceMirror
instances in the heap graph. It first checks if the instances have already been added to the context using a predefined key. If they have not been added, it finds the class IDs for the KeyedWeakReference
class and a legacy KeyedWeakReference
class. It retrieves the heap dump uptime milliseconds using the heapDumpUptimeMillis
method. It then filters the instances in the heap graph to select those that belong to either the KeyedWeakReference
class or the legacy KeyedWeakReference
class. These instances are mapped to KeyedWeakReferenceMirror
instances using the fromInstance
method and added to the context. The added instances are returned as the result.
package shark
import shark.ObjectInspectors.KEYED_WEAK_REFERENCE
import shark.internal.KeyedWeakReferenceMirror
/**
* Finds all objects tracked by a KeyedWeakReference, ie all objects that were passed to
* ObjectWatcher.watch.
*/
object KeyedWeakReferenceFinder : LeakingObjectFinder {
override fun findLeakingObjectIds(graph: HeapGraph): Set<Long> =
findKeyedWeakReferences(graph)
.filter { it.hasReferent && it.isRetained }
.map { it.referent.value }
.toSet()
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) {
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.instanceClassId == keyedWeakReferenceClassId || instance.instanceClassId == legacyKeyedWeakReferenceClassId
}
.map {
KeyedWeakReferenceMirror.fromInstance(
it, heapDumpUptimeMillis
)
}
.toList()
graph.context[KEYED_WEAK_REFERENCE.name] = addedToContext
addedToContext
}
}
}