Accidentally I have stumbled into a change in Java 15 that I was not aware of. Suppose I have a very simple question: what is the size of an array of 3 integers? For this, I use JOL. The code is fairly trivial:
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
public class Array {
public static void main(String [] args){
int [] array = new int[3];
System.out.println(ClassLayout.parseInstance(array).toPrintable());
}
}
I run this with Java 13:
java -Djdk.attach.allowAttachSelf -Djol.tryWithSudo=true -cp jol-cli.jar Array.java
I get the output:
[I object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 18 0e 07 00 (00011000 00001110 00000111 00000000) (462360)
12 4 (object header) 03 00 00 00 (00000011 00000000 00000000 00000000) (3)
16 12 int [I.<elements> N/A
28 4 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
This is pretty much obvious:
12 bytes --> Object headers
4 bytes --> size of array
12 bytes --> elements of array themselves
4 bytes --> padding to align by 8 bytes
----
32 bytes total
Running this example with Java 15 yields the same output, same 32 bytes. Expected...
For the second part, I want to disable a JVM optimization: -XX:-UseCompressedOops. I run this with Java 13:
java -Djdk.attach.allowAttachSelf -Djol.tryWithSudo=true -cp jol-cli.jar -XX:-UseCompressedOops Array.java
[I object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 11 00 00 00 (00010001 00000000 00000000 00000000) (17)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 40 0c f0 33 (01000000 00001100 11110000 00110011) (871369792)
12 4 (object header) 02 00 00 00 (00000010 00000000 00000000 00000000) (2)
16 4 (object header) 03 00 00 00 (00000011 00000000 00000000 00000000) (3)
20 4 (alignment/padding gap)
24 12 int [I.<elements> N/A
36 4 (loss due to the next object alignment)
Instance size: 40 bytes
Space losses: 4 bytes internal + 4 bytes external = 8 bytes total
Well, sort of expected too:
16 bytes --> object headers (I did -XX:-UseCompressedOops after all)
4 bytes --> array size
4 bytes --> alignment for array headers (AFAIK this is only done for arrays)
12 bytes --> array elements themselves
4 bytes --> 4 bytes padding
----
40 bytes total
Now let's run the same example with Java 15:
[I object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 0e 09 00 00 (00001110 00001001 00000000 00000000) (2318)
12 4 (object header) 03 00 00 00 (00000011 00000000 00000000 00000000) (3)
16 12 int [I.<elements> N/A
28 4 (loss due to the next object alignment)
Instance size: 32 bytes
Why is this 32 bytes now? How come not 40, just like with Java 13?
In both Java 13 and Java 15, both of these options are on by default:
When
-XX:-UseCompressedOopsis disabled, it means thatUseCompressedClassPointersis disabled also. That is why whenUseCompressedOopsis turned off, the header size goes up by4 bytes, becauseUseCompressedOopsturns offUseCompressedClassPointers. At least this is how it is in Java 13:Things have changed in Java 15:
So disabling
UseCompressedOopsdoes not mean thatUseCompressedClassPointersis disabled also, so it stays at4 bytes.Though, I answered this myself, it would be nice if someone finds the relevant bug/change for this? I have not been successful in that, so far.