理解Java中的对象分配

时间:2018-01-11 06:37:38

标签: java performance object dynamic-memory-allocation jit

我使用的是64位Ubuntu 14,Intel Core i5。

我编写了以下简单程序来理解对象分配在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("");
        }
    }
}

我按如下方式运行此程序:

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

在查看编译后的代码后,我想知道对象分配是如何发生的(编译代码片段):

  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}

以下new Object()标记为mov %r12d,0xc(%rsi)

看起来此时内存已经分配了r12d的地址。

问题是为什么我们mov地址到[rsi+0xc]内存位置。

但据我所知,在linux中分配一些内存我们必须执行sys_brk系统调用。我们在这里做的只是简单的mov指令,我在这里看不到任何syscall。为什么简单mov表示new Object()

对象分配如何在JVM中工作?

1 个答案:

答案 0 :(得分:2)

给定的片段不完整。实际的分配代码应该在这个片段的正上方。

mov %r12d,0xc(%rsi)是分配序列的最后一条指令 - 它只是将新对象的最后一个填充字清零。

我已经在thisthisthis答案中描述了HotSpot中对象分配的工作原理。由于JVM不依赖于系统分配器,因此您不会在那里看到任何系统调用。它在预分配区域中使用自己的内存管理 - Java Heap。

以下是C2编译代码中分配序列的外观。评论是我的。

    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)