Add compact-strings module: Compact Strings (JEP 254) measured with JOL on JDK 25, with and without -XX:-CompactStrings, and compact object headers on 25 vs 27
Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01KqJyCidz3ZgRyHABv2GVJh
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import java.lang.reflect.Field;
|
||||
import org.openjdk.jol.info.ClassLayout;
|
||||
import org.openjdk.jol.info.GraphLayout;
|
||||
import org.openjdk.jol.vm.VM;
|
||||
|
||||
/**
|
||||
* What one String really costs: the String object, the byte[] it points to, and the coder byte that says how to read it.
|
||||
* Measured with JOL (org.openjdk.jol:jol-core). Run by run.sh under several JVM flag sets.
|
||||
*/
|
||||
public class StringLayout {
|
||||
|
||||
static byte coder(String s) throws Exception {
|
||||
Field f = String.class.getDeclaredField("coder");
|
||||
f.setAccessible(true); // needs --add-opens java.base/java.lang=ALL-UNNAMED
|
||||
return f.getByte(s);
|
||||
}
|
||||
|
||||
static byte[] value(String s) throws Exception {
|
||||
Field f = String.class.getDeclaredField("value");
|
||||
f.setAccessible(true);
|
||||
return (byte[]) f.get(s);
|
||||
}
|
||||
|
||||
static String repeat(char c, int n) { return String.valueOf(c).repeat(n); }
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("java.version = " + System.getProperty("java.version"));
|
||||
System.out.println("vm.flags = " + String.join(" ", java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments()
|
||||
.stream().filter(a -> a.startsWith("-XX")).toList()));
|
||||
System.out.println(VM.current().details().lines().filter(l -> l.startsWith("# Objects are 8 bytes") || l.startsWith("# Field sizes")
|
||||
|| l.contains("Array element") || l.contains("compressed")).reduce("", (a, b) -> a + b + "\n"));
|
||||
|
||||
System.out.println("=== java.lang.String, the class");
|
||||
System.out.println(ClassLayout.parseClass(String.class).toPrintable());
|
||||
|
||||
System.out.println("=== one Latin-1 string and one UTF-16 string, field by field");
|
||||
System.out.println(ClassLayout.parseInstance("hello").toPrintable());
|
||||
System.out.println(ClassLayout.parseInstance("h\u20ACllo").toPrintable());
|
||||
|
||||
System.out.println("=== the byte[] behind each");
|
||||
System.out.println(ClassLayout.parseInstance(value("hello")).toPrintable());
|
||||
System.out.println(ClassLayout.parseInstance(value("h\u20ACllo")).toPrintable());
|
||||
|
||||
System.out.println("=== footprint by length (String object + its byte[], via GraphLayout)");
|
||||
System.out.println("chars content coder byte[].length String byte[] total");
|
||||
for (int n : new int[] {0, 1, 5, 10, 20, 40, 100, 1000}) {
|
||||
for (char c : new char[] {'a', '\u00E9', '\u20AC'}) { // a = ASCII, e-acute = Latin-1 supplement, euro = needs UTF-16
|
||||
String s = new String(repeat(c, n).toCharArray()); // a fresh object, never the interned literal
|
||||
long total = GraphLayout.parseInstance(s).totalSize();
|
||||
long str = ClassLayout.parseInstance(s).instanceSize();
|
||||
long arr = ClassLayout.parseInstance(value(s)).instanceSize();
|
||||
System.out.printf("%5d %-8s %5d %13d %6d %6d %5d%n", n,
|
||||
c == 'a' ? "ASCII" : c == '\u00E9' ? "U+00E9" : "U+20AC", coder(s), value(s).length, str, arr, total);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user