<lambda>null1package shark.internal 2 3 import shark.HeapGraph 4 import shark.HeapObject.HeapInstance 5 6 internal class AndroidNativeSizeMapper(private val graph: HeapGraph) { 7 8 /** 9 * Returns a map of Object id to native size as tracked by NativeAllocationRegistry$CleanerThunk 10 */ 11 fun mapNativeSizes(): Map<Long, Int> { 12 return graph.context.getOrPut("AndroidNativeSizeMapper") { 13 buildNativeSizeMap() 14 } 15 } 16 17 private fun buildNativeSizeMap(): Map<Long, Int> { 18 val nativeSizes = mutableMapOf<Long, Int>() 19 // Doc from perflib: 20 // Native allocations can be identified by looking at instances of 21 // libcore.util.NativeAllocationRegistry$CleanerThunk. The "owning" Java object is the 22 // "referent" field of the "sun.misc.Cleaner" instance with a hard reference to the 23 // CleanerThunk. 24 // 25 // The size is in the 'size' field of the libcore.util.NativeAllocationRegistry instance 26 // that the CleanerThunk has a pointer to. The native pointer is in the 'nativePtr' field of 27 // the CleanerThunk. The hprof does not include the native bytes pointed to. 28 graph.findClassByName("sun.misc.Cleaner")?.let { cleanerClass -> 29 cleanerClass.directInstances.forEach { cleaner -> 30 val thunkField = cleaner["sun.misc.Cleaner", "thunk"] 31 val thunkId = thunkField?.value?.asNonNullObjectId 32 val referentId = 33 cleaner["java.lang.ref.Reference", "referent"]?.value?.asNonNullObjectId 34 if (thunkId != null && referentId != null) { 35 val thunkRecord = thunkField.value.asObject 36 if (thunkRecord is HeapInstance && thunkRecord instanceOf "libcore.util.NativeAllocationRegistry\$CleanerThunk") { 37 val allocationRegistryIdField = 38 thunkRecord["libcore.util.NativeAllocationRegistry\$CleanerThunk", "this\$0"] 39 if (allocationRegistryIdField != null && allocationRegistryIdField.value.isNonNullReference) { 40 val allocationRegistryRecord = allocationRegistryIdField.value.asObject 41 if (allocationRegistryRecord is HeapInstance && allocationRegistryRecord instanceOf "libcore.util.NativeAllocationRegistry") { 42 var nativeSize = nativeSizes[referentId] ?: 0 43 nativeSize += allocationRegistryRecord["libcore.util.NativeAllocationRegistry", "size"]?.value?.asLong?.toInt() 44 ?: 0 45 nativeSizes[referentId] = nativeSize 46 } 47 } 48 } 49 } 50 } 51 } 52 return nativeSizes 53 } 54 55 companion object { 56 fun mapNativeSizes(heapGraph: HeapGraph): Map<Long, Int> { 57 return AndroidNativeSizeMapper(heapGraph).mapNativeSizes() 58 } 59 } 60 } 61