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,91 @@
|
||||
$ java StringLayout (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
vm.flags = -XX:+EnableDynamicAgentLoading
|
||||
# Field sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
|
||||
=== java.lang.String, the class
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 (object header: class) N/A
|
||||
12 4 int String.hash N/A
|
||||
16 1 byte String.coder N/A
|
||||
17 1 boolean String.hashIsZero N/A
|
||||
18 2 (alignment/padding gap)
|
||||
20 4 byte[] String.value N/A
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total
|
||||
|
||||
=== one Latin-1 string and one UTF-16 string, field by field
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x00176520
|
||||
12 4 int String.hash 0
|
||||
16 1 byte String.coder 0
|
||||
17 1 boolean String.hashIsZero false
|
||||
18 2 (alignment/padding gap)
|
||||
20 4 byte[] String.value [104, 101, 108, 108, 111]
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total
|
||||
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x00176520
|
||||
12 4 int String.hash 0
|
||||
16 1 byte String.coder 1
|
||||
17 1 boolean String.hashIsZero false
|
||||
18 2 (alignment/padding gap)
|
||||
20 4 byte[] String.value [104, 0, -84, 32, 108, 0, 108, 0, 111, 0]
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total
|
||||
|
||||
=== the byte[] behind each
|
||||
[B object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x00173550
|
||||
12 4 (array length) 5
|
||||
16 5 byte [B.<elements> N/A
|
||||
21 3 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
|
||||
|
||||
[B object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x00173550
|
||||
12 4 (array length) 10
|
||||
16 10 byte [B.<elements> N/A
|
||||
26 6 (object alignment gap)
|
||||
Instance size: 32 bytes
|
||||
Space losses: 0 bytes internal + 6 bytes external = 6 bytes total
|
||||
|
||||
=== footprint by length (String object + its byte[], via GraphLayout)
|
||||
chars content coder byte[].length String byte[] total
|
||||
0 ASCII 0 0 24 16 40
|
||||
0 U+00E9 0 0 24 16 40
|
||||
0 U+20AC 0 0 24 16 40
|
||||
1 ASCII 0 1 24 24 48
|
||||
1 U+00E9 0 1 24 24 48
|
||||
1 U+20AC 1 2 24 24 48
|
||||
5 ASCII 0 5 24 24 48
|
||||
5 U+00E9 0 5 24 24 48
|
||||
5 U+20AC 1 10 24 32 56
|
||||
10 ASCII 0 10 24 32 56
|
||||
10 U+00E9 0 10 24 32 56
|
||||
10 U+20AC 1 20 24 40 64
|
||||
20 ASCII 0 20 24 40 64
|
||||
20 U+00E9 0 20 24 40 64
|
||||
20 U+20AC 1 40 24 56 80
|
||||
40 ASCII 0 40 24 56 80
|
||||
40 U+00E9 0 40 24 56 80
|
||||
40 U+20AC 1 80 24 96 120
|
||||
100 ASCII 0 100 24 120 144
|
||||
100 U+00E9 0 100 24 120 144
|
||||
100 U+20AC 1 200 24 216 240
|
||||
1000 ASCII 0 1000 24 1016 1040
|
||||
1000 U+00E9 0 1000 24 1016 1040
|
||||
1000 U+20AC 1 2000 24 2016 2040
|
||||
@@ -0,0 +1,91 @@
|
||||
$ java -XX:-CompactStrings StringLayout (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
vm.flags = -XX:+EnableDynamicAgentLoading -XX:-CompactStrings
|
||||
# Field sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
|
||||
=== java.lang.String, the class
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 (object header: class) N/A
|
||||
12 4 int String.hash N/A
|
||||
16 1 byte String.coder N/A
|
||||
17 1 boolean String.hashIsZero N/A
|
||||
18 2 (alignment/padding gap)
|
||||
20 4 byte[] String.value N/A
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total
|
||||
|
||||
=== one Latin-1 string and one UTF-16 string, field by field
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x4d001e38
|
||||
12 4 int String.hash 0
|
||||
16 1 byte String.coder 1
|
||||
17 1 boolean String.hashIsZero false
|
||||
18 2 (alignment/padding gap)
|
||||
20 4 byte[] String.value [104, 0, 101, 0, 108, 0, 108, 0, 111, 0]
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total
|
||||
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x4d001e38
|
||||
12 4 int String.hash 0
|
||||
16 1 byte String.coder 1
|
||||
17 1 boolean String.hashIsZero false
|
||||
18 2 (alignment/padding gap)
|
||||
20 4 byte[] String.value [104, 0, -84, 32, 108, 0, 108, 0, 111, 0]
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total
|
||||
|
||||
=== the byte[] behind each
|
||||
[B object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x4d000a00
|
||||
12 4 (array length) 10
|
||||
16 10 byte [B.<elements> N/A
|
||||
26 6 (object alignment gap)
|
||||
Instance size: 32 bytes
|
||||
Space losses: 0 bytes internal + 6 bytes external = 6 bytes total
|
||||
|
||||
[B object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x4d000a00
|
||||
12 4 (array length) 10
|
||||
16 10 byte [B.<elements> N/A
|
||||
26 6 (object alignment gap)
|
||||
Instance size: 32 bytes
|
||||
Space losses: 0 bytes internal + 6 bytes external = 6 bytes total
|
||||
|
||||
=== footprint by length (String object + its byte[], via GraphLayout)
|
||||
chars content coder byte[].length String byte[] total
|
||||
0 ASCII 1 0 24 16 40
|
||||
0 U+00E9 1 0 24 16 40
|
||||
0 U+20AC 1 0 24 16 40
|
||||
1 ASCII 1 2 24 24 48
|
||||
1 U+00E9 1 2 24 24 48
|
||||
1 U+20AC 1 2 24 24 48
|
||||
5 ASCII 1 10 24 32 56
|
||||
5 U+00E9 1 10 24 32 56
|
||||
5 U+20AC 1 10 24 32 56
|
||||
10 ASCII 1 20 24 40 64
|
||||
10 U+00E9 1 20 24 40 64
|
||||
10 U+20AC 1 20 24 40 64
|
||||
20 ASCII 1 40 24 56 80
|
||||
20 U+00E9 1 40 24 56 80
|
||||
20 U+20AC 1 40 24 56 80
|
||||
40 ASCII 1 80 24 96 120
|
||||
40 U+00E9 1 80 24 96 120
|
||||
40 U+20AC 1 80 24 96 120
|
||||
100 ASCII 1 200 24 216 240
|
||||
100 U+00E9 1 200 24 216 240
|
||||
100 U+20AC 1 200 24 216 240
|
||||
1000 ASCII 1 2000 24 2016 2040
|
||||
1000 U+00E9 1 2000 24 2016 2040
|
||||
1000 U+20AC 1 2000 24 2016 2040
|
||||
@@ -0,0 +1,89 @@
|
||||
$ java -XX:+UseCompactObjectHeaders StringLayout (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
vm.flags = -XX:+EnableDynamicAgentLoading -XX:+UseCompactObjectHeaders
|
||||
# Field sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
|
||||
=== java.lang.String, the class
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 int String.hash N/A
|
||||
12 1 byte String.coder N/A
|
||||
13 1 boolean String.hashIsZero N/A
|
||||
14 2 (alignment/padding gap)
|
||||
16 4 byte[] String.value N/A
|
||||
20 4 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total
|
||||
|
||||
=== one Latin-1 string and one UTF-16 string, field by field
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0017940000000001 (Lilliput)
|
||||
8 4 int String.hash 0
|
||||
12 1 byte String.coder 0
|
||||
13 1 boolean String.hashIsZero false
|
||||
14 2 (alignment/padding gap)
|
||||
16 4 byte[] String.value [104, 101, 108, 108, 111]
|
||||
20 4 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total
|
||||
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0017940000000001 (Lilliput)
|
||||
8 4 int String.hash 0
|
||||
12 1 byte String.coder 1
|
||||
13 1 boolean String.hashIsZero false
|
||||
14 2 (alignment/padding gap)
|
||||
16 4 byte[] String.value [104, 0, -84, 32, 108, 0, 108, 0, 111, 0]
|
||||
20 4 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total
|
||||
|
||||
=== the byte[] behind each
|
||||
[B object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x00174c0000000001 (Lilliput)
|
||||
8 4 (array length) 5
|
||||
12 5 byte [B.<elements> N/A
|
||||
17 7 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 0 bytes internal + 7 bytes external = 7 bytes total
|
||||
|
||||
[B object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x00174c0000000001 (Lilliput)
|
||||
8 4 (array length) 10
|
||||
12 10 byte [B.<elements> N/A
|
||||
22 2 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total
|
||||
|
||||
=== footprint by length (String object + its byte[], via GraphLayout)
|
||||
chars content coder byte[].length String byte[] total
|
||||
0 ASCII 0 0 24 16 40
|
||||
0 U+00E9 0 0 24 16 40
|
||||
0 U+20AC 0 0 24 16 40
|
||||
1 ASCII 0 1 24 16 40
|
||||
1 U+00E9 0 1 24 16 40
|
||||
1 U+20AC 1 2 24 16 40
|
||||
5 ASCII 0 5 24 24 48
|
||||
5 U+00E9 0 5 24 24 48
|
||||
5 U+20AC 1 10 24 24 48
|
||||
10 ASCII 0 10 24 24 48
|
||||
10 U+00E9 0 10 24 24 48
|
||||
10 U+20AC 1 20 24 32 56
|
||||
20 ASCII 0 20 24 32 56
|
||||
20 U+00E9 0 20 24 32 56
|
||||
20 U+20AC 1 40 24 56 80
|
||||
40 ASCII 0 40 24 56 80
|
||||
40 U+00E9 0 40 24 56 80
|
||||
40 U+20AC 1 80 24 96 120
|
||||
100 ASCII 0 100 24 112 136
|
||||
100 U+00E9 0 100 24 112 136
|
||||
100 U+20AC 1 200 24 216 240
|
||||
1000 ASCII 0 1000 24 1016 1040
|
||||
1000 U+00E9 0 1000 24 1016 1040
|
||||
1000 U+20AC 1 2000 24 2016 2040
|
||||
@@ -0,0 +1,89 @@
|
||||
$ java -XX:+UseCompactObjectHeaders -XX:-CompactStrings StringLayout (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
vm.flags = -XX:+EnableDynamicAgentLoading -XX:+UseCompactObjectHeaders -XX:-CompactStrings
|
||||
# Field sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
|
||||
=== java.lang.String, the class
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 int String.hash N/A
|
||||
12 1 byte String.coder N/A
|
||||
13 1 boolean String.hashIsZero N/A
|
||||
14 2 (alignment/padding gap)
|
||||
16 4 byte[] String.value N/A
|
||||
20 4 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total
|
||||
|
||||
=== one Latin-1 string and one UTF-16 string, field by field
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0008540000000001 (Lilliput)
|
||||
8 4 int String.hash 0
|
||||
12 1 byte String.coder 1
|
||||
13 1 boolean String.hashIsZero false
|
||||
14 2 (alignment/padding gap)
|
||||
16 4 byte[] String.value [104, 0, 101, 0, 108, 0, 108, 0, 111, 0]
|
||||
20 4 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total
|
||||
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0008540000000001 (Lilliput)
|
||||
8 4 int String.hash 0
|
||||
12 1 byte String.coder 1
|
||||
13 1 boolean String.hashIsZero false
|
||||
14 2 (alignment/padding gap)
|
||||
16 4 byte[] String.value [104, 0, -84, 32, 108, 0, 108, 0, 111, 0]
|
||||
20 4 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total
|
||||
|
||||
=== the byte[] behind each
|
||||
[B object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0008140000000001 (Lilliput)
|
||||
8 4 (array length) 10
|
||||
12 10 byte [B.<elements> N/A
|
||||
22 2 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total
|
||||
|
||||
[B object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0008140000000001 (Lilliput)
|
||||
8 4 (array length) 10
|
||||
12 10 byte [B.<elements> N/A
|
||||
22 2 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total
|
||||
|
||||
=== footprint by length (String object + its byte[], via GraphLayout)
|
||||
chars content coder byte[].length String byte[] total
|
||||
0 ASCII 1 0 24 16 40
|
||||
0 U+00E9 1 0 24 16 40
|
||||
0 U+20AC 1 0 24 16 40
|
||||
1 ASCII 1 2 24 16 40
|
||||
1 U+00E9 1 2 24 16 40
|
||||
1 U+20AC 1 2 24 16 40
|
||||
5 ASCII 1 10 24 24 48
|
||||
5 U+00E9 1 10 24 24 48
|
||||
5 U+20AC 1 10 24 24 48
|
||||
10 ASCII 1 20 24 32 56
|
||||
10 U+00E9 1 20 24 32 56
|
||||
10 U+20AC 1 20 24 32 56
|
||||
20 ASCII 1 40 24 56 80
|
||||
20 U+00E9 1 40 24 56 80
|
||||
20 U+20AC 1 40 24 56 80
|
||||
40 ASCII 1 80 24 96 120
|
||||
40 U+00E9 1 80 24 96 120
|
||||
40 U+20AC 1 80 24 96 120
|
||||
100 ASCII 1 200 24 216 240
|
||||
100 U+00E9 1 200 24 216 240
|
||||
100 U+20AC 1 200 24 216 240
|
||||
1000 ASCII 1 2000 24 2016 2040
|
||||
1000 U+00E9 1 2000 24 2016 2040
|
||||
1000 U+20AC 1 2000 24 2016 2040
|
||||
@@ -0,0 +1,90 @@
|
||||
$ java StringLayout (JDK 27)
|
||||
java.version = 27
|
||||
vm.flags = -XX:+EnableDynamicAgentLoading
|
||||
# WARNING: Unable to attach Serviceability Agent. sun.jvm.hotspot.runtime.VM.isCompressedKlassPointersEnabled()
|
||||
# Field sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
|
||||
=== java.lang.String, the class
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 int String.hash N/A
|
||||
12 1 byte String.coder N/A
|
||||
13 1 boolean String.hashIsZero N/A
|
||||
14 2 (alignment/padding gap)
|
||||
16 4 byte[] String.value N/A
|
||||
20 4 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total
|
||||
|
||||
=== one Latin-1 string and one UTF-16 string, field by field
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0017cc0000000001 (Lilliput)
|
||||
8 4 int String.hash 0
|
||||
12 1 byte String.coder 0
|
||||
13 1 boolean String.hashIsZero false
|
||||
14 2 (alignment/padding gap)
|
||||
16 4 byte[] String.value [104, 101, 108, 108, 111]
|
||||
20 4 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total
|
||||
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0017cc0000000001 (Lilliput)
|
||||
8 4 int String.hash 0
|
||||
12 1 byte String.coder 1
|
||||
13 1 boolean String.hashIsZero false
|
||||
14 2 (alignment/padding gap)
|
||||
16 4 byte[] String.value [104, 0, -84, 32, 108, 0, 108, 0, 111, 0]
|
||||
20 4 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total
|
||||
|
||||
=== the byte[] behind each
|
||||
[B object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0017980000000001 (Lilliput)
|
||||
8 4 (array length) 5
|
||||
12 5 byte [B.<elements> N/A
|
||||
17 7 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 0 bytes internal + 7 bytes external = 7 bytes total
|
||||
|
||||
[B object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0017980000000001 (Lilliput)
|
||||
8 4 (array length) 10
|
||||
12 10 byte [B.<elements> N/A
|
||||
22 2 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total
|
||||
|
||||
=== footprint by length (String object + its byte[], via GraphLayout)
|
||||
chars content coder byte[].length String byte[] total
|
||||
0 ASCII 0 0 24 16 40
|
||||
0 U+00E9 0 0 24 16 40
|
||||
0 U+20AC 0 0 24 16 40
|
||||
1 ASCII 0 1 24 16 40
|
||||
1 U+00E9 0 1 24 16 40
|
||||
1 U+20AC 1 2 24 16 40
|
||||
5 ASCII 0 5 24 24 48
|
||||
5 U+00E9 0 5 24 24 48
|
||||
5 U+20AC 1 10 24 24 48
|
||||
10 ASCII 0 10 24 24 48
|
||||
10 U+00E9 0 10 24 24 48
|
||||
10 U+20AC 1 20 24 32 56
|
||||
20 ASCII 0 20 24 32 56
|
||||
20 U+00E9 0 20 24 32 56
|
||||
20 U+20AC 1 40 24 56 80
|
||||
40 ASCII 0 40 24 56 80
|
||||
40 U+00E9 0 40 24 56 80
|
||||
40 U+20AC 1 80 24 96 120
|
||||
100 ASCII 0 100 24 112 136
|
||||
100 U+00E9 0 100 24 112 136
|
||||
100 U+20AC 1 200 24 216 240
|
||||
1000 ASCII 0 1000 24 1016 1040
|
||||
1000 U+00E9 0 1000 24 1016 1040
|
||||
1000 U+20AC 1 2000 24 2016 2040
|
||||
@@ -0,0 +1,92 @@
|
||||
$ java -XX:-UseCompactObjectHeaders StringLayout (JDK 27)
|
||||
java.version = 27
|
||||
vm.flags = -XX:+EnableDynamicAgentLoading -XX:-UseCompactObjectHeaders
|
||||
# WARNING: Unable to attach Serviceability Agent. sun.jvm.hotspot.runtime.VM.isCompressedKlassPointersEnabled()
|
||||
# Field sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
|
||||
|
||||
=== java.lang.String, the class
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) N/A
|
||||
8 4 (object header: class) N/A
|
||||
12 4 int String.hash N/A
|
||||
16 1 byte String.coder N/A
|
||||
17 1 boolean String.hashIsZero N/A
|
||||
18 2 (alignment/padding gap)
|
||||
20 4 byte[] String.value N/A
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total
|
||||
|
||||
=== one Latin-1 string and one UTF-16 string, field by field
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x0017b7d8
|
||||
12 4 int String.hash 0
|
||||
16 1 byte String.coder 0
|
||||
17 1 boolean String.hashIsZero false
|
||||
18 2 (alignment/padding gap)
|
||||
20 4 byte[] String.value [104, 101, 108, 108, 111]
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total
|
||||
|
||||
java.lang.String object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x0017b7d8
|
||||
12 4 int String.hash 0
|
||||
16 1 byte String.coder 1
|
||||
17 1 boolean String.hashIsZero false
|
||||
18 2 (alignment/padding gap)
|
||||
20 4 byte[] String.value [104, 0, -84, 32, 108, 0, 108, 0, 111, 0]
|
||||
Instance size: 24 bytes
|
||||
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total
|
||||
|
||||
=== the byte[] behind each
|
||||
[B object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000009 (non-biasable; age: 1)
|
||||
8 4 (object header: class) 0x00178240
|
||||
12 4 (array length) 5
|
||||
16 5 byte [B.<elements> N/A
|
||||
21 3 (object alignment gap)
|
||||
Instance size: 24 bytes
|
||||
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
|
||||
|
||||
[B object internals:
|
||||
OFF SZ TYPE DESCRIPTION VALUE
|
||||
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
|
||||
8 4 (object header: class) 0x00178240
|
||||
12 4 (array length) 10
|
||||
16 10 byte [B.<elements> N/A
|
||||
26 6 (object alignment gap)
|
||||
Instance size: 32 bytes
|
||||
Space losses: 0 bytes internal + 6 bytes external = 6 bytes total
|
||||
|
||||
=== footprint by length (String object + its byte[], via GraphLayout)
|
||||
chars content coder byte[].length String byte[] total
|
||||
0 ASCII 0 0 24 16 40
|
||||
0 U+00E9 0 0 24 16 40
|
||||
0 U+20AC 0 0 24 16 40
|
||||
1 ASCII 0 1 24 24 48
|
||||
1 U+00E9 0 1 24 24 48
|
||||
1 U+20AC 1 2 24 24 48
|
||||
5 ASCII 0 5 24 24 48
|
||||
5 U+00E9 0 5 24 24 48
|
||||
5 U+20AC 1 10 24 32 56
|
||||
10 ASCII 0 10 24 32 56
|
||||
10 U+00E9 0 10 24 32 56
|
||||
10 U+20AC 1 20 24 40 64
|
||||
20 ASCII 0 20 24 40 64
|
||||
20 U+00E9 0 20 24 40 64
|
||||
20 U+20AC 1 40 24 56 80
|
||||
40 ASCII 0 40 24 56 80
|
||||
40 U+00E9 0 40 24 56 80
|
||||
40 U+20AC 1 80 24 96 120
|
||||
100 ASCII 0 100 24 120 144
|
||||
100 U+00E9 0 100 24 120 144
|
||||
100 U+20AC 1 200 24 216 240
|
||||
1000 ASCII 0 1000 24 1016 1040
|
||||
1000 U+00E9 0 1000 24 1016 1040
|
||||
1000 U+20AC 1 2000 24 2016 2040
|
||||
@@ -0,0 +1,8 @@
|
||||
$ java -Xmx3g MillionStrings (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
strings : 1,000,000 (average 42.50 chars)
|
||||
coder == 0 (LATIN1) in set A : 1,000,000
|
||||
coder == 1 (UTF16) in set B : 1,000,000
|
||||
A: lower-case ASCII only : 89,844,680 bytes (89.8 MB, 89.8 bytes per string)
|
||||
B: same + one euro sign : 133,839,824 bytes (133.8 MB, 133.8 bytes per string)
|
||||
B / A : 1.490
|
||||
@@ -0,0 +1,8 @@
|
||||
$ java -Xmx3g -XX:-CompactStrings MillionStrings (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
strings : 1,000,000 (average 42.50 chars)
|
||||
coder == 0 (LATIN1) in set A : 0
|
||||
coder == 1 (UTF16) in set B : 1,000,000
|
||||
A: lower-case ASCII only : 131,995,184 bytes (132.0 MB, 132.0 bytes per string)
|
||||
B: same + one euro sign : 133,839,824 bytes (133.8 MB, 133.8 bytes per string)
|
||||
B / A : 1.014
|
||||
@@ -0,0 +1,8 @@
|
||||
$ java -Xmx3g -XX:+UseCompactObjectHeaders MillionStrings (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
strings : 1,000,000 (average 42.50 chars)
|
||||
coder == 0 (LATIN1) in set A : 1,000,000
|
||||
coder == 1 (UTF16) in set B : 1,000,000
|
||||
A: lower-case ASCII only : 86,150,520 bytes (86.2 MB, 86.2 bytes per string)
|
||||
B: same + one euro sign : 130,145,168 bytes (130.1 MB, 130.1 bytes per string)
|
||||
B / A : 1.511
|
||||
@@ -0,0 +1,8 @@
|
||||
$ java -Xmx3g -XX:+UseCompactObjectHeaders -XX:-CompactStrings MillionStrings (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
strings : 1,000,000 (average 42.50 chars)
|
||||
coder == 0 (LATIN1) in set A : 0
|
||||
coder == 1 (UTF16) in set B : 1,000,000
|
||||
A: lower-case ASCII only : 127,997,304 bytes (128.0 MB, 128.0 bytes per string)
|
||||
B: same + one euro sign : 130,145,168 bytes (130.1 MB, 130.1 bytes per string)
|
||||
B / A : 1.017
|
||||
@@ -0,0 +1,9 @@
|
||||
$ java -Xmx3g MillionStrings (JDK 27)
|
||||
java.version = 27
|
||||
strings : 1,000,000 (average 42.50 chars)
|
||||
coder == 0 (LATIN1) in set A : 1,000,000
|
||||
coder == 1 (UTF16) in set B : 1,000,000
|
||||
# WARNING: Unable to attach Serviceability Agent. sun.jvm.hotspot.runtime.VM.isCompressedKlassPointersEnabled()
|
||||
A: lower-case ASCII only : 86,150,520 bytes (86.2 MB, 86.2 bytes per string)
|
||||
B: same + one euro sign : 130,145,168 bytes (130.1 MB, 130.1 bytes per string)
|
||||
B / A : 1.511
|
||||
@@ -0,0 +1,9 @@
|
||||
$ java -Xmx3g -XX:-UseCompactObjectHeaders MillionStrings (JDK 27)
|
||||
java.version = 27
|
||||
strings : 1,000,000 (average 42.50 chars)
|
||||
coder == 0 (LATIN1) in set A : 1,000,000
|
||||
coder == 1 (UTF16) in set B : 1,000,000
|
||||
# WARNING: Unable to attach Serviceability Agent. sun.jvm.hotspot.runtime.VM.isCompressedKlassPointersEnabled()
|
||||
A: lower-case ASCII only : 89,844,680 bytes (89.8 MB, 89.8 bytes per string)
|
||||
B: same + one euro sign : 133,839,824 bytes (133.8 MB, 133.8 bytes per string)
|
||||
B / A : 1.490
|
||||
@@ -0,0 +1,39 @@
|
||||
$ java Upgrade (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
"hello" (literal) length=5 coder=0 byte[].length=5
|
||||
"h\u00E9llo" (e-acute, Latin-1 supplement) length=5 coder=0 byte[].length=5
|
||||
"h\u20ACllo" (euro sign) length=5 coder=1 byte[].length=10
|
||||
"hello" + "\u20AC" (concat) length=6 coder=1 byte[].length=12
|
||||
wide = "\u20ACabcdef" length=7 coder=1 byte[].length=14
|
||||
wide.substring(1) (all Latin-1 again) length=6 coder=0 byte[].length=6
|
||||
wide.replace('\u20AC', 'E') length=7 coder=0 byte[].length=7
|
||||
wide.toLowerCase() length=7 coder=1 byte[].length=14
|
||||
new String("caf\u00E9".getBytes(UTF_8), UTF_8) length=4 coder=0 byte[].length=4
|
||||
new String(utf8 bytes of ASCII, UTF_8) length=5 coder=0 byte[].length=5
|
||||
new String(char[] {'a','b'}) length=2 coder=0 byte[].length=2
|
||||
new String(char[] {'a','\u4E2D'}) length=2 coder=1 byte[].length=4
|
||||
"\uD83D\uDE00" (emoji, a surrogate pair) length=2 coder=1 byte[].length=4
|
||||
StringBuilder("ascii only").toString() length=10 coder=0 byte[].length=10
|
||||
... after append('\u20AC'), toString() length=11 coder=1 byte[].length=22
|
||||
... after setLength(0) + ASCII, toString() length=13 coder=0 byte[].length=13
|
||||
length() of the emoji: 2 (UTF-16 code units, not code points)
|
||||
|
||||
$ java -XX:-CompactStrings Upgrade (JDK 25)
|
||||
java.version = 25.0.4.1
|
||||
"hello" (literal) length=5 coder=1 byte[].length=10
|
||||
"h\u00E9llo" (e-acute, Latin-1 supplement) length=5 coder=1 byte[].length=10
|
||||
"h\u20ACllo" (euro sign) length=5 coder=1 byte[].length=10
|
||||
"hello" + "\u20AC" (concat) length=6 coder=1 byte[].length=12
|
||||
wide = "\u20ACabcdef" length=7 coder=1 byte[].length=14
|
||||
wide.substring(1) (all Latin-1 again) length=6 coder=1 byte[].length=12
|
||||
wide.replace('\u20AC', 'E') length=7 coder=1 byte[].length=14
|
||||
wide.toLowerCase() length=7 coder=1 byte[].length=14
|
||||
new String("caf\u00E9".getBytes(UTF_8), UTF_8) length=4 coder=1 byte[].length=8
|
||||
new String(utf8 bytes of ASCII, UTF_8) length=5 coder=1 byte[].length=10
|
||||
new String(char[] {'a','b'}) length=2 coder=1 byte[].length=4
|
||||
new String(char[] {'a','\u4E2D'}) length=2 coder=1 byte[].length=4
|
||||
"\uD83D\uDE00" (emoji, a surrogate pair) length=2 coder=1 byte[].length=4
|
||||
StringBuilder("ascii only").toString() length=10 coder=1 byte[].length=20
|
||||
... after append('\u20AC'), toString() length=11 coder=1 byte[].length=22
|
||||
... after setLength(0) + ASCII, toString() length=13 coder=1 byte[].length=26
|
||||
length() of the emoji: 2 (UTF-16 code units, not code points)
|
||||
@@ -0,0 +1,18 @@
|
||||
$ java -XX:+PrintFlagsFinal -version | grep -E 'CompactStrings|CompactObjectHeaders' (JDK 25)
|
||||
bool CompactStrings = true {pd product} {default}
|
||||
bool UseCompactObjectHeaders = false {product lp64_product} {default}
|
||||
|
||||
$ java -XX:-CompactStrings -version (JDK 25)
|
||||
openjdk version "25.0.4.1" 2026-08-18 LTS
|
||||
OpenJDK Runtime Environment Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS)
|
||||
OpenJDK 64-Bit Server VM Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS, mixed mode)
|
||||
|
||||
$ java -XX:+PrintFlagsFinal -version | grep -E 'CompactStrings|CompactObjectHeaders' (JDK 27)
|
||||
bool CompactStrings = true {pd product} {default}
|
||||
bool UseCompactObjectHeaders = true {product lp64_product} {default}
|
||||
|
||||
$ java -XX:-CompactStrings -version (JDK 27)
|
||||
openjdk version "27" 2026-09-15
|
||||
OpenJDK Runtime Environment Corretto-27.0.0.35.1 (build 27+35-FR)
|
||||
OpenJDK 64-Bit Server VM Corretto-27.0.0.35.1 (build 27+35-FR, mixed mode)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
machine: 2 CPUs, Intel(R) Xeon(R) Processor @ 2.10GHz
|
||||
|
||||
$ java org.openjdk.jmh.Main -f 2 -wi 3 -w 1 -i 5 -r 1 (25.0.4.1+1-LTS, JMH 1.37)
|
||||
Benchmark Mode Cnt Score Error Units
|
||||
StringBench.compareToLastCharDiffers avgt 10 13.515 ± 0.096 ns/op
|
||||
StringBench.concatTwo avgt 10 75.682 ± 1.184 ns/op
|
||||
StringBench.equalsSameContent avgt 10 8.563 ± 0.179 ns/op
|
||||
StringBench.indexOfAbsentString avgt 10 36.571 ± 0.238 ns/op
|
||||
StringBench.indexOfLastChar avgt 10 2.872 ± 0.092 ns/op
|
||||
StringBench.toUpper avgt 10 276.137 ± 11.187 ns/op
|
||||
|
||||
$ java -XX:-CompactStrings org.openjdk.jmh.Main -f 2 -wi 3 -w 1 -i 5 -r 1 (25.0.4.1+1-LTS, JMH 1.37)
|
||||
Benchmark Mode Cnt Score Error Units
|
||||
StringBench.compareToLastCharDiffers avgt 10 16.630 ± 1.244 ns/op
|
||||
StringBench.concatTwo avgt 10 142.990 ± 2.788 ns/op
|
||||
StringBench.equalsSameContent avgt 10 14.370 ± 0.857 ns/op
|
||||
StringBench.indexOfAbsentString avgt 10 71.265 ± 1.693 ns/op
|
||||
StringBench.indexOfLastChar avgt 10 3.677 ± 0.308 ns/op
|
||||
StringBench.toUpper avgt 10 558.868 ± 21.992 ns/op
|
||||
Reference in New Issue
Block a user