有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java为什么jvm XX:+EliminateAllocations失败

上浆试验。爪哇

public class OnStackTest {

    public static void alloc() {
        User u = new User();
        u.id = 5;
        u.name = "test";
    }
    public static void main(String[] args) throws InterruptedException {
        long b = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            Thread.sleep(50);
            alloc();
        }
        long e = System.currentTimeMillis();
        System.out.println(e - b);
    }
}

用户。爪哇

public class User {
    public int id = 0;

    public String name = "";

    public User() {
    }
    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

JVM标志 -server -Xmx10m -Xms10m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:-UseTLAB -XX:+EliminateAllocations

使用jmap -histo

发现用户对象一直都是在堆上创建的。理论上,我们不应该用标量替换用户对象,也不应该在堆上创建对象


共 (1) 个答案

  1. # 1 楼答案

    默认情况下DoEscapeAnalysisEliminateAllocations标志处于启用状态-无需显式设置它们

    EliminateAllocations标志特定于C2编译器,它在c2_globals.hpp中声明。但是在您的测试中,C2很长一段时间都没有编译该方法。添加-XX:+PrintCompilation标志以确保:

        ...
       1045   84       3       java.lang.StringBuffer::<init> (6 bytes)
       1045   85  s    3       java.lang.StringBuffer::toString (36 bytes)
       1045   86       3       java.util.Arrays::copyOf (19 bytes)
      15666   87     n 0       java.lang.Thread::sleep (native)   (static)
      15714   88       3       OnStackTest::alloc (20 bytes)
     311503   89       4       OnStackTest::alloc (20 bytes)
     311505   88       3       OnStackTest::alloc (20 bytes)   made not entrant
    

    这表明alloc在15秒后由C1(第3层)编译。一个方法需要调用数千次,然后才能考虑由C2重新编译。考虑到迭代之间有50毫秒的延迟,这种情况不会很快发生。在我的实验中,alloc仅在运行5分钟后由C2编译

    C2编译方法不再包含分配
    我用-XX:CompileCommand="print,OnStackTest::alloc"验证了这一点

      # {method} {0x0000000012de2bc0} 'alloc' '()V' in 'OnStackTest'
      #           [sp+0x20]  (sp of caller)
      0x0000000003359fc0: sub     rsp,18h
      0x0000000003359fc7: mov     qword ptr [rsp+10h],rbp  ;*synchronization entry
                                                    ; - OnStackTest::alloc@-1 (line 4)
    
      0x0000000003359fcc: add     rsp,10h
      0x0000000003359fd0: pop     rbp
      0x0000000003359fd1: test    dword ptr [0df0000h],eax
                                                    ;   {poll_return}
      0x0000000003359fd7: ret
    

    顺便说一句,我建议使用JMH进行此类测试。否则,很容易陷入一个常见的基准测试陷阱。这里有一个similar question也试图衡量分配消除的效果,但它错了