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 楼答案
默认情况下
DoEscapeAnalysis
和EliminateAllocations
标志处于启用状态-无需显式设置它们EliminateAllocations
标志特定于C2编译器,它在c2_globals.hpp中声明。但是在您的测试中,C2很长一段时间都没有编译该方法。添加-XX:+PrintCompilation
标志以确保:这表明
alloc
在15秒后由C1(第3层)编译。一个方法需要调用数千次,然后才能考虑由C2重新编译。考虑到迭代之间有50毫秒的延迟,这种情况不会很快发生。在我的实验中,alloc
仅在运行5分钟后由C2编译C2编译方法不再包含分配
我用
-XX:CompileCommand="print,OnStackTest::alloc"
验证了这一点顺便说一句,我建议使用JMH进行此类测试。否则,很容易陷入一个常见的基准测试陷阱。这里有一个similar question也试图衡量分配消除的效果,但它错了