Understanding object allocation in Java

0

I'm using Ubuntu 14 64 bit, Intel Core i5.

I wrote the following simple program to understand how object allocation works in Java:

public class App {
    public static void main(String[] args) {
        for(int i = 0; i < Integer.MAX_VALUE; i++)
            testObjectCreationCompiled();
    }

    public static void testObjectCreationCompiled() {
        Object obj = new Object();
        if (obj.hashCode() == System.nanoTime()) {
            System.out.print("");
        }
    }
}

I run this program as follows:

java -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*App.testObjectCreationCompiled -server -jar target/test-1.0.0.jar 

After looking at the compiled code I was wondering how the object allocation happened here (fragment of compiled code):

  0x00007f60651165e4: mov     %r12d,0xc(%rsi)   ;*new  ; - com.test.App::testObjectCreationCompiled@0 (line 13)

  0x00007f60651165e8: mov     (%rsi),%r10
  0x00007f60651165eb: mov     %r10,%r11
  0x00007f60651165ee: and     $0x7,%r11
  0x00007f60651165f2: cmp     $0x1,%r11
  0x00007f60651165f6: jne     0x7f606511662a
  0x00007f60651165f8: shr     $0x8,%r10
  0x00007f60651165fc: mov     %r10d,%ebp
  0x00007f60651165ff: and     $0x7fffffff,%ebp
  0x00007f6065116605: test    %ebp,%ebp
  0x00007f6065116607: je      0x7f606511662a    ;*invokevirtual hashCode
                                                ; - com.test.App::testObjectCreationCompiled@9 (line 14)

  0x00007f6065116609: movabs  $0x7f6079d5d440,%r10
  0x00007f6065116613: callq   %r10              ;*invokestatic nanoTime
                                                ; - com.test.App::testObjectCreationCompiled@13 (line 14)

  0x00007f6065116616: movsxd  %ebp,%r10         ;*i2l  ; - com.test.App::testObjectCreationCompiled@12 (line 14)

  0x00007f6065116619: cmp     %rax,%r10
  0x00007f606511661c: je      0x7f6065116649    ;*ifne
                                                ; - com.test.App::testObjectCreationCompiled@17 (line 14)

  0x00007f606511661e: add     $0x10,%rsp
  0x00007f6065116622: pop     %rbp
  0x00007f6065116623: test    %eax,0x15f3d9d7(%rip)  ;   {poll_return}
  0x00007f6065116629: retq
  0x00007f606511662a: nop
  0x00007f606511662b: callq   0x7f6065046020    ; OopMap{off=144}
                                                ;*invokevirtual hashCode
                                                ; - com.test.App::testObjectCreationCompiled@9 (line 14)
                                                ;   {optimized virtual_call}
  0x00007f6065116630: mov     %eax,%ebp
  0x00007f6065116632: jmp     0x7f6065116609
  0x00007f6065116634: movabs  $0x100000f28,%rsi  ;   {metadata('java/lang/Object')}
  0x00007f606511663e: nop
  0x00007f606511663f: callq   0x7f6065100fa0    ; OopMap{off=164}
                                                ;*new  ; - com.test.App::testObjectCreationCompiled@0 (line 13)
                                                ;   {runtime_call}

Here is the new Object() is marked as just mov %r12d,0xc(%rsi).

It looks like the memory was already allocated at this point with the address at r12d.

The question is why do we mov the address to [rsi+0xc] memory location.

But as far as I know to allocate some memory in linux we have to perform sys_brk syscall. What we do here is just simple mov instruction, I dont see any syscall here ever. Why simple mov means new Object()?

How does object allocation work in JVM?

java
performance
object
dynamic-memory-allocation
jit
asked on Stack Overflow Jan 11, 2018 by St.Antario • edited Jan 11, 2018 by St.Antario

1 Answer

2

The given fragment is incomplete. The actual allocation code should be right above this fragment.

mov %r12d,0xc(%rsi) is the last instruction of allocation sequence - it just zeroes the last padding word of the new object.

I've already decribed how object allocation works in HotSpot in this, this and this answers. You won't see any syscalls there since JVM does not rely on system allocator. It uses its own memory management in the preallocated region - Java Heap.

Here is how allocation sequence typically looks like in C2-compiled code. The comments are mine.

    mov    0x60(%r15),%rdx        ; obj = currentThread.tlab_top
    mov    %rdx,%r10
    add    $0x10,%r10             ; r10 = obj + sizeof(java/lang/Object)
    cmp    0x70(%r15),%r10        ; if (r10 >= currentThread.tlab_end)
    jae    0x00000000030ad2f4     ;     goto slow_case
    mov    %r10,0x60(%r15)        ; currentThread.tlab_top = r10

    prefetchnta 0xc0(%r10)        ; prefetch memory next to tlab_top into CPU caches
                                  ; to make subsequent allocations faster

    mov    $0x200001e5,%r10d      ; r10 = VMKlass of java/lang/Object
    shl    $0x3,%r10
    mov    0xa8(%r10),%r10        ; r10 = Header prototype for java/lang/Object
    mov    %r10,(%rdx)            ; obj[0] = r10 (header prototype)
    movl   $0x200001e5,0x8(%rdx)  ; obj[8] = VMKlass of java/lang/Object
    mov    %r12d,0xc(%rdx)        ; obj[12] = 0 (padding to 8-byte boundary)
answered on Stack Overflow Jan 11, 2018 by apangin

User contributions licensed under CC BY-SA 3.0