Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions shark/shark-cli/src/main/java/shark/InteractiveCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ class InteractiveCommand : CliktCommand(
else -> heapObject.instances
}.count()
val plural = if (instanceCount != 1) "s" else ""
"$CLASS ${heapObject.name}@${heapObject.objectId} (${instanceCount} instance$plural)"
"$CLASS ${heapObject.name}@${heapObject.objectId.asObjectIdString()} (${instanceCount} instance$plural)"
}
is HeapInstance -> {
val asJavaString = heapObject.readAsJavaString()
Expand All @@ -530,16 +530,16 @@ class InteractiveCommand : CliktCommand(
" \"${asJavaString}\""
} else ""

"$INSTANCE ${heapObject.instanceClassSimpleName}@${heapObject.objectId}$value"
"$INSTANCE ${heapObject.instanceClassSimpleName}@${heapObject.objectId.asObjectIdString()}$value"
}
is HeapObjectArray -> {
val className = heapObject.arrayClassSimpleName.removeSuffix("[]")
"$ARRAY $className[${heapObject.readElements().count()}]@${heapObject.objectId}"
"$ARRAY $className[${heapObject.readElements().count()}]@${heapObject.objectId.asObjectIdString()}"
}
is HeapPrimitiveArray -> {
val record = heapObject.readRecord()
val primitiveName = heapObject.primitiveType.name.lowercase(Locale.US)
"$ARRAY $primitiveName[${record.size}]@${heapObject.objectId}"
"$ARRAY $primitiveName[${record.size}]@${heapObject.objectId.asObjectIdString()}"
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions shark/shark-graph/api/shark-graph.api
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,7 @@ public final class shark/HprofIndex$Companion {
public static synthetic fun indexRecordsOf$default (Lshark/HprofIndex$Companion;Lshark/DualSourceProvider;Lshark/HprofHeader;Lshark/ProguardMapping;Ljava/util/Set;Lshark/CancelSignal;ILjava/lang/Object;)Lshark/HprofIndex;
}

public final class shark/ObjectIdFormattingKt {
public static final fun asObjectIdString (J)Ljava/lang/String;
}

2 changes: 1 addition & 1 deletion shark/shark-graph/src/main/java/shark/HeapObject.kt
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ sealed class HeapObject {
}

override fun toString(): String {
return "instance @$objectId of $instanceClassName"
return "instance @${objectId.asObjectIdString()} of $instanceClassName"
}
}

Expand Down
2 changes: 1 addition & 1 deletion shark/shark-graph/src/main/java/shark/HprofHeapGraph.kt
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ class HprofHeapGraph internal constructor(

override fun findObjectById(objectId: Long): HeapObject {
return findObjectByIdOrNull(objectId) ?: throw IllegalArgumentException(
"Object id $objectId not found in heap dump."
"Object id ${objectId.asObjectIdString()} not found in heap dump."
)
}

Expand Down
8 changes: 8 additions & 0 deletions shark/shark-graph/src/main/java/shark/ObjectIdFormatting.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package shark

private const val LOW_32_BITS = 0xFFFFFFFFL

fun Long.asObjectIdString(): String {
val address = if (this < 0L) this and LOW_32_BITS else this
return "$this (0x${address.toString(16)})"
}
4 changes: 2 additions & 2 deletions shark/shark/src/main/java/shark/RealLeakTracerFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ class RealLeakTracerFactory constructor(
): List<String> {
val subLeakedLabels = groupByClassName(subLeakedObjectIds).map { (className, objectIds) ->
if (objectIds.size == 1) {
"Also retains leaking object ${objectIds.single()} ($className)"
"Also retains leaking object ${objectIds.single().asObjectIdString()} ($className)"
} else {
"Also retains ${objectIds.size} leaking $className objects"
}
Expand All @@ -506,7 +506,7 @@ class RealLeakTracerFactory constructor(
val alsoRetainingLabels =
groupByClassName(alsoRetainingObjectIds).map { (className, objectIds) ->
if (objectIds.size == 1) {
"Also retained by leaking object ${objectIds.single()} ($className), which has its own" +
"Also retained by leaking object ${objectIds.single().asObjectIdString()} ($className), which has its own" +
" leak trace"
} else {
"Also retained by ${objectIds.size} leaking $className objects, which have their own" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class HeapAnalysisStringRenderingTest {
|Please include this in bug reports and Stack Overflow questions.
|
|Analysis duration: \d* ms
|Heap dump file path: ${hprofFile.absolutePath}
|Heap dump file path: ${Pattern.quote(hprofFile.absolutePath)}
|Heap dump timestamp: \d*
|Heap dump duration: Unknown
|===================================="""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ class OpenJdkInstanceRefReadersTest {

with(refPath.first()) {
assertThat(referenceDisplayName).matches(
"\\[instance @\\d* of shark\\.OpenJdkInstanceRefReadersTest\\\$SomeKey]"
"\\[instance @\\d* \\(0x[0-9a-f]+\\) of shark\\.OpenJdkInstanceRefReadersTest\\\$SomeKey\\]"
)
}
}
Expand Down Expand Up @@ -414,7 +414,9 @@ class OpenJdkInstanceRefReadersTest {

with(refPath[0]) {
assertThat(owningClassName).isEqualTo(WeakHashMap::class.qualifiedName)
assertThat(referenceDisplayName).matches("\\[instance @\\d* of shark\\.OpenJdkInstanceRefReadersTest\\\$SomeKey]")
assertThat(referenceDisplayName).matches(
"\\[instance @\\d* \\(0x[0-9a-f]+\\) of shark\\.OpenJdkInstanceRefReadersTest\\\$SomeKey\\]"
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class PrioritizingShortestPathFinderTest {
val leakingObject = leakTraces.single().leakingObject
assertThat(leakingObject.className).isEqualTo("Parent")
assertThat(leakingObject.labels).contains(
"Also retains leaking object $childObjectId (Child)"
"Also retains leaking object ${childObjectId.asObjectIdString()} (Child)"
)
}

Expand Down Expand Up @@ -78,7 +78,7 @@ class PrioritizingShortestPathFinderTest {
// Only Child says so: the path it's reached through isn't in either leak trace, and Parent has
// its own path to explain rather than the leaking objects it happens to also retain.
assertThat(leakTraces.getValue("Child").leakingObject.labels).contains(
"Also retained by leaking object $parentObjectId (Parent), which has its own leak trace"
"Also retained by leaking object ${parentObjectId.asObjectIdString()} (Parent), which has its own leak trace"
)
assertThat(leakTraces.getValue("Parent").leakingObject.labels).noneMatch {
it.startsWith("Also retain")
Expand Down