java - 了解 Java 中的对象分配

标签 java performance object dynamic-memory-allocation jit

我使用的是 Ubuntu 14 64 位、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 中的对象分配是如何工作的?

最佳答案

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

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

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

以下是 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)

关于java - 了解 Java 中的对象分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48201116/

相关文章:

javascript - 这是一个好的 JavaScript 对象模型吗? (电话簿项目)

Java fillRect() 不一致

javascript - 展平/展开对象 : am I on the right tracks?

c++ - HashMap 错误: no match for call to ‘(const __gnu_cxx::

java - 如何打印 HashMap 中的键列表?

oracle - 发现使用 oracle 临时表空间的进程/查询

javascript - 使用 JS 提高性能

java - 在抽象类中同步静态方法

java - Maven 似乎使用的版本比我预期的版本旧

Java - 日期格式的正则表达式?