8306591: SA and hotspot generate different hprof records for GC roots

Reviewed-by: cjplummer, dholmes
This commit is contained in:
Yasumasa Suenaga 2026-02-24 03:01:19 +00:00
parent 171d788bce
commit f25d429c8d
5 changed files with 49 additions and 2 deletions

View File

@ -408,6 +408,8 @@
volatile_nonstatic_field(ClassLoaderData, _klasses, Klass*) \
nonstatic_field(ClassLoaderData, _has_class_mirror_holder, bool) \
\
static_field(ClassLoaderData, _the_null_class_loader_data, ClassLoaderData*) \
\
volatile_static_field(ClassLoaderDataGraph, _head, ClassLoaderData*) \
\
/**********/ \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -44,12 +44,14 @@ public class ClassLoaderData extends VMObject {
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
Type type = db.lookupType("ClassLoaderData");
classLoaderFieldOffset = type.getAddressField("_class_loader").getOffset();
theNullClassLoaderDataField = type.getAddressField("_the_null_class_loader_data");
nextField = type.getAddressField("_next");
klassesField = new MetadataField(type.getAddressField("_klasses"), 0);
hasClassMirrorHolderField = new CIntField(type.getCIntegerField("_has_class_mirror_holder"), 0);
}
private static long classLoaderFieldOffset;
private static AddressField theNullClassLoaderDataField;
private static AddressField nextField;
private static MetadataField klassesField;
private static CIntField hasClassMirrorHolderField;
@ -75,6 +77,10 @@ public class ClassLoaderData extends VMObject {
return hasClassMirrorHolderField.getValue(this) != 0;
}
public static ClassLoaderData theNullClassLoaderData() {
return instantiateWrapperFor(theNullClassLoaderDataField.getValue());
}
public ClassLoaderData next() {
return instantiateWrapperFor(nextField.getValue(getAddress()));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -121,6 +121,9 @@ public abstract class AbstractHeapGraphWriter implements HeapGraphWriter {
// write JNI global handles
writeGlobalJNIHandles();
// write classes in null class loader data
writeStickyClasses();
} catch (RuntimeException re) {
handleRuntimeException(re);
}
@ -168,6 +171,9 @@ public abstract class AbstractHeapGraphWriter implements HeapGraphWriter {
}
}
protected void writeStickyClasses() throws IOException {
}
protected void writeGlobalJNIHandle(Address handleAddr) throws IOException {
}

View File

@ -967,6 +967,22 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
}
}
@Override
protected void writeStickyClasses() throws IOException {
ClassLoaderData.theNullClassLoaderData().classesDo(k -> {
if (k instanceof InstanceKlass) {
try {
int size = 1 + (int)VM.getVM().getAddressSize();
writeHeapRecordPrologue(size);
out.writeByte((byte)HPROF_GC_ROOT_STICKY_CLASS);
writeClassID(k);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
});
}
protected void writeObjectArray(ObjArray array) throws IOException {
int headerSize = getArrayHeaderSize(true);
final int length = calculateArrayMaxLength(array.getLength(),
@ -1304,6 +1320,10 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
writeObjectID(address);
}
private void writeClassID(Klass k) throws IOException {
writeObjectID(k.getJavaMirror());
}
private void writeSymbolID(Symbol sym) throws IOException {
assert names.contains(sym);
long address = (sym != null) ? getAddressValue(sym.getAddress()) : getAddressValue(null);

View File

@ -81,10 +81,23 @@ public class ClhsdbDumpheap {
fail("HPROF_GC_ROOT_JAVA_FRAME not found");
}
private static void verifyStickyClasses(String file) throws IOException {
try (var snapshot = HprofReader.readFile(file, false, 0)) {
for (var root = snapshot.getRoots(); root.hasMoreElements();) {
if (root.nextElement().getType() == Root.SYSTEM_CLASS) {
// expected
return;
}
}
}
fail("HPROF_GC_ROOT_STICKY_CLASS not found");
}
private static void verifyDumpFile(File dump) throws Exception {
assertTrue(dump.exists() && dump.isFile(), "Could not create dump file " + dump.getAbsolutePath());
printStackTraces(dump.getAbsolutePath());
verifyLocalRefs(dump.getAbsolutePath());
verifyStickyClasses(dump.getAbsolutePath());
}
private static class SubTest {