sizeOf() calculation from ClassLayout seems to be wrong
Volker Simonis
volker.simonis at gmail.com
Tue Jun 7 08:59:17 UTC 2016
On Tue, Jun 7, 2016 at 2:47 AM, Enis Söztutar <enis.soz at gmail.com> wrote:
> Hi,
>
> I was testing ClassLayout with small byte[]'s, and noticed something with a
> byte[] size of 9:
>
> [B 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) f5 00 00 f8 (11110101
> 00000000 00000000 11111000) (-134217483)
>
> 12 4 (object header) 11 00 00 00 (00010001
> 00000000 00000000 00000000) (17)
>
> 16 17 byte [B.<elements> N/A
>
> 33 7 (loss due to the next object alignment)
>
> Instance size: 40 bytes
>
> Space losses: 0 bytes internal + 7 bytes external = 7 bytes total
>
> We seem to be calculating an extra 8 bytes in the byte[] layout after the
> header. The instance size is calculated as 40, however,
> VM.current().sizeOf() returns 32.
Hi Enis,
I'm not sure what ClassLayout is reporting, but after the header, an
array first has its length field (which is an int) and thereafter the
array elements begin on a 8-byte aligned address.
So if you're running without compressed oops you have the following layout:
(gdb) call find($r3)
"Executing find"
0x00003ffe3fe99458 is an oop
[B
{0x00003ffe3fe99458} - klass: {type array byte}
- length: 9
- 0: 1
- 1: 2
- 2: 3
- 3: 4
- 4: 5
- 5: 6
- 6: 7
- 7: 8
- 8: 9
(gdb) x /12x $r3
0x3ffe3fe99458: 0x00000001 0x00000000 0x167007d0 0x00003ffe
0x3ffe3fe99468: 0x00000009 0x00000000 0x04030201 0x08070605
0x3ffe3fe99478: 0x00000009 0x00000000 0xbaadbabe 0xbaadbabe
The first 16 bytes are the object header. At address 0x3ffe3fe99468
you have the arrays size (9) and at 0x3ffe3fe99470 the start of the
array elements. Notice the you loose 4 bytes because the start of the
elements has to be 8-byte aligned. Also the array is padded with 4
bytes at the end to finish at a 8-byte aligned address. So in total
the array occupies 40 bytes in the heap.
With compressed oops, the layout looks as follows:
(gdb) call find($r3)
"Executing find"
0x00000000c3e1a928 is an oop
[B
{0x00000000c3e1a928} - klass: {type array byte}
- length: 9
- 0: 1
- 1: 2
- 2: 3
- 3: 4
- 4: 5
- 5: 6
- 6: 7
- 7: 8
- 8: 9
(gdb) x /12x $r3
0xc3e1a928: 0x00000001 0x00000000 0x200000fa 0x00000009
0xc3e1a938: 0x04030201 0x08070605 0x00000009 0x00000000
0xc3e1a948: 0xbaadbabe 0xbaadbabe 0xbaadbabe 0xbaadbabe
Now the object header is 12 bytes and the arrays length field fits
into the first 16 bytes. The array elements start at 0xc3e1a938 but
again they have to finish at an 8-byte aligned address so they are
padded with 4 bytes at the end. In total, the array occupies 32 bytes
in compressed oops mode.
Regards,
Volker
PS: gdb is your friend :) If you happen to be in Tallin the next days
you can come and hear
http://2016.geekout.ee/schedule/hotspot-debugging-at-the-os-level (or
watch an older version online:
https://www.youtube.com/watch?v=JZpEskA_89U)
>
>
> This little UT also fails with the latest source code base:
>
> public class ArraySizeTest {
>
> @Test
>
> public void testByteArraySize() {
>
> System.err.println(VM.current().details()); // debug
>
> for (int i = 0; i < 100; i++) {
>
> byte[] b = new byte[i];
>
> long vmSize = VM.current().sizeOf(i);
>
> long clSize = ClassLayout.parseInstance(b).instanceSize();
>
> Assert.assertEquals("sizeOf() from VM and ClassLayout does not match,
> VM.sizeOf()="
>
> + vmSize + ", ClassLayout.instanceSize()=" + clSize, vmSize, clSize
> );
>
> }
>
> }
>
> }
>
> I was not able to open a JIRA issue for this, figured I can report here.
>
> Thanks,
>
> Enis
More information about the jol-dev
mailing list