Buy the T-shirt |
Context
The thread discusses False Sharing as described here. It is pointed out that the padding is one sided and padding using inheritance is demonstrated as solution. The merits of using inheritance vs. using an array and utilizing Unsafe to access middle element (see Disruptor's Sequence) vs. using AtomicLongArray to achieve the same effect are discussed (I think the inheritance option is best, as explored here). And then confusion erupts...What's my layout?
At this point Peter L. makes the following point:
[...]in fact the best option may be.What follows is a series of suggestions on what the layout of this class may be.
class Client1 {
private long value;
public long[] padding = new long[5];
}
Option 1: My recollections
I was too lazy to check and from memory penned the following:
[...] the ordering of the fields may end up shifting the reference (if it's 32bit or CompressedOop) next to the header to fill the pad required for the value field. The end layout may well be:
12b header
4b padding(oop)
8b value
Option 2: Simon's recollections
[...] I thought Hotspot was laying out longs before
references, and that the object header was 8 Bytes.
So I would expect Client1 to be laid out in this way:
8B header
8B value
4B padding (oop)
[...] Am I out of date in object layout and header size ?
Option 3: TM Jee's doubts
for:To which Peter L. wisely replied:
class Client1 {
private long value;
public long[] padding = new long[5]
public Object[] o = new Object[1];
}
the memory layout should be something like
12b header (or is it 16b)
8b value
4b for the long[] (its just the reference which is 4b for compressed and 8b if not)
4b for the Object[] (again it's just the reference)
Is this right so far?
Yes. But as you recognise the sizes of the header and sizes of references are not known until runtime.
Option 4: Check...
So I used JOL to check. And as it turns out we are all somewhat right and somewhat wrong...I'm right for compressed oops (the default for 64bit):
Running 64-bit HotSpot VM.
Using compressed references with 3-bit shift.
Client1 object internals:
OFFSET SIZE TYPE DESCRIPTION
0 4 (object header)
4 4 (object header)
8 4 (object header)
12 4 long[] Client1.padding
16 8 long Client1.value
24 4 Object[] Client1.o
28 4 (loss due to the next object alignment)
The header is 12b and the array reference is shifted up to save on space. But my casual assumption 32bit JVM layout will be the same is wrong.
Simon is right that the header is 8b (but only for 32bit JVMs) and that references will go at the end (for both 32bit and 64bit, but not with compressed oops):
Running 32-bit HotSpot VM.
Client1 object internals:
OFFSET SIZE TYPE DESCRIPTION
0 4 (object header)
4 4 (object header)
8 8 long Client1.value
16 4 long[] Client1.padding
20 4 Object[] Client1.o
And finally with 64bit Mr. Jee is right too:
Running 64-bit HotSpot VM.
Client1 object internals:
OFFSET SIZE TYPE DESCRIPTION
0 4 (object header)
4 4 (object header)
8 4 (object header)
12 4 (object header)
16 8 long Client1.value
24 8 long[] Client1.padding
32 8 Object[] Client1.o
And Peter is entirely right to point out the runtime is the crucial variable in this equation.
Lesson?
If you catch yourself wondering about object layout:
- Use JOL to check, it's better than memorizing rules
- Remember that 32/64/64+Oops are different for Hotspot, and other JVMs may have different layouts altogether
- Read another post about java memory layout