When inspecting a java object, clhsdb prints "Oop for..." twice for each field that is an oop. It also prints the address of the java object twice. The following example show this when inspecting the java.lang.System Class instance, which we get to via the InstanceKlass mirror:
hsdb> class java.lang.System
java/lang/System @0x000000080000f388
hsdb> inspect 0x000000080000f388
Type is InstanceKlass (size of 480)
...
OopHandle Klass::_java_mirror: OopHandle @ 0x000000080000f400
...
hsdb> examine 0x000000080000f400
0x000000080000f400: 0x00007fd8b812e5e8
hsdb> examine 0x00007fd8b812e5e8
0x00007fd8b812e5e8: 0x00000007fef00770
hsdb> inspect 0x00000007fef00770
instance of Oop for java/lang/Class @ 0x00000007fef00770 @ 0x00000007fef00770 (size = 160)
in: Oop for java/io/BufferedInputStream @ 0x0000000082005b08 Oop for java/io/BufferedInputStream @ 0x0000000082005b08
out: Oop for java/io/PrintStream @ 0x0000000082007b60 Oop for java/io/PrintStream @ 0x0000000082007b60
err: Oop for java/io/PrintStream @ 0x000000008200e0c8 Oop for java/io/PrintStream @ 0x000000008200e0c8
...
For the first line of output where the address of Oop is printed twice, the issue is in the implementation of the "inspect" command:
out.println("instance of " + node.getValue() + " @ " + a +
" (size = " + oop.getObjectSize() + ")");
node.getValue() already includes the address, so no need for this println to also do it. The address comes from the following in Oop.printOopValueOn():
obj.printValueOn(tty);
tty.print(" @ " + VM.getVM().getUniverse().heap().oopAddressDescription(obj.getHandle()));
For the lines that follow, which are all Oop fields of the class, this issue also stems from the fact that Oop.printOopValueOn() is used, and not only does it include the address, but it also includes the "Oop for" part by calling Oop.printValueOn():
public void printValueOn(PrintStream tty) {
(new Throwable()).printStackTrace(tty);
try {
tty.print("Oop for " + getKlass().getName().asString());
} catch (java.lang.NullPointerException e) {
tty.print("Oop");
}
And this is the stack when it is called:
at jdk.hotspot.agent/sun.jvm.hotspot.oops.Oop.printValueOn(Oop.java:187)
at jdk.hotspot.agent/sun.jvm.hotspot.oops.Instance.printValueOn(Instance.java:79)
at jdk.hotspot.agent/sun.jvm.hotspot.oops.Oop.printOopValueOn(Oop.java:168)
at jdk.hotspot.agent/sun.jvm.hotspot.ui.tree.OopTreeNodeAdapter.getValue(OopTreeNodeAdapter.java:107)
at jdk.hotspot.agent/sun.jvm.hotspot.ui.tree.FieldTreeNodeAdapter.toString(FieldTreeNodeAdapter.java:62)
at java.base/java.lang.String.valueOf(String.java:3365)
at java.base/java.io.PrintStream.print(PrintStream.java:877)
at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor$Command.printNode(CommandProcessor.java:289)
at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor$23.doit(CommandProcessor.java:1062)
at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor.executeCommand(CommandProcessor.java:2060)
at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor.executeCommand(CommandProcessor.java:2030)
at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor.run(CommandProcessor.java:1910)
The second "Oop for" and the second address comes from CommandProcessor.printOopValue():
if (s != null) {
out.print("Oop for " + s.asString() + " @ ");
} else {
out.print("Oop @ ");
}
Oop.printOopAddressOn(oop, out);
Although the real problem is that this code is called in the first place from CommandProcessor.printNode():
if (field instanceof OopTreeNodeAdapter) {
out.print(field);
out.print(" ");
printOopValue(((OopTreeNodeAdapter)field).getOop());
out.println();
} else {
out.println(field);
}
It should instead just unconditionally call out.println(field), which will trigger calling Oop.printOopValueOn(), which will include something like "Oop for java/io/PrintStream @ 0x0000000082007b60"
hsdb> class java.lang.System
java/lang/System @0x000000080000f388
hsdb> inspect 0x000000080000f388
Type is InstanceKlass (size of 480)
...
OopHandle Klass::_java_mirror: OopHandle @ 0x000000080000f400
...
hsdb> examine 0x000000080000f400
0x000000080000f400: 0x00007fd8b812e5e8
hsdb> examine 0x00007fd8b812e5e8
0x00007fd8b812e5e8: 0x00000007fef00770
hsdb> inspect 0x00000007fef00770
instance of Oop for java/lang/Class @ 0x00000007fef00770 @ 0x00000007fef00770 (size = 160)
in: Oop for java/io/BufferedInputStream @ 0x0000000082005b08 Oop for java/io/BufferedInputStream @ 0x0000000082005b08
out: Oop for java/io/PrintStream @ 0x0000000082007b60 Oop for java/io/PrintStream @ 0x0000000082007b60
err: Oop for java/io/PrintStream @ 0x000000008200e0c8 Oop for java/io/PrintStream @ 0x000000008200e0c8
...
For the first line of output where the address of Oop is printed twice, the issue is in the implementation of the "inspect" command:
out.println("instance of " + node.getValue() + " @ " + a +
" (size = " + oop.getObjectSize() + ")");
node.getValue() already includes the address, so no need for this println to also do it. The address comes from the following in Oop.printOopValueOn():
obj.printValueOn(tty);
tty.print(" @ " + VM.getVM().getUniverse().heap().oopAddressDescription(obj.getHandle()));
For the lines that follow, which are all Oop fields of the class, this issue also stems from the fact that Oop.printOopValueOn() is used, and not only does it include the address, but it also includes the "Oop for" part by calling Oop.printValueOn():
public void printValueOn(PrintStream tty) {
(new Throwable()).printStackTrace(tty);
try {
tty.print("Oop for " + getKlass().getName().asString());
} catch (java.lang.NullPointerException e) {
tty.print("Oop");
}
And this is the stack when it is called:
at jdk.hotspot.agent/sun.jvm.hotspot.oops.Oop.printValueOn(Oop.java:187)
at jdk.hotspot.agent/sun.jvm.hotspot.oops.Instance.printValueOn(Instance.java:79)
at jdk.hotspot.agent/sun.jvm.hotspot.oops.Oop.printOopValueOn(Oop.java:168)
at jdk.hotspot.agent/sun.jvm.hotspot.ui.tree.OopTreeNodeAdapter.getValue(OopTreeNodeAdapter.java:107)
at jdk.hotspot.agent/sun.jvm.hotspot.ui.tree.FieldTreeNodeAdapter.toString(FieldTreeNodeAdapter.java:62)
at java.base/java.lang.String.valueOf(String.java:3365)
at java.base/java.io.PrintStream.print(PrintStream.java:877)
at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor$Command.printNode(CommandProcessor.java:289)
at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor$23.doit(CommandProcessor.java:1062)
at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor.executeCommand(CommandProcessor.java:2060)
at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor.executeCommand(CommandProcessor.java:2030)
at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor.run(CommandProcessor.java:1910)
The second "Oop for" and the second address comes from CommandProcessor.printOopValue():
if (s != null) {
out.print("Oop for " + s.asString() + " @ ");
} else {
out.print("Oop @ ");
}
Oop.printOopAddressOn(oop, out);
Although the real problem is that this code is called in the first place from CommandProcessor.printNode():
if (field instanceof OopTreeNodeAdapter) {
out.print(field);
out.print(" ");
printOopValue(((OopTreeNodeAdapter)field).getOop());
out.println();
} else {
out.println(field);
}
It should instead just unconditionally call out.println(field), which will trigger calling Oop.printOopValueOn(), which will include something like "Oop for java/io/PrintStream @ 0x0000000082007b60"
- relates to
-
JDK-8297975 String pattern used in ClhsdbInspect.java is too liberal
-
- Closed
-