Java JIT是否可以使用final boolean取消跳转?

3
我们知道,有些人说Java的JIT比C++更快。我有一些想法,可以利用JIT在运行时删除一些指令。
以下是我尝试的示例代码:
/**
 * Created by kadirbasol on 4/6/14.
 */
public class RemoveJump {
    public final boolean test;

    private static RemoveJump instance = new RemoveJump();

    public static final RemoveJump getInstance() {
        return instance;
    }

    private RemoveJump() {
        //set the test on the constructor once and
        //remove this if statement forever from testLoop
        test = false;
    }


    public final long getData() {
        return 1000000000;
    }

    public final void testLoop() {
        long l = System.currentTimeMillis();
        int ppp = 0;
        long count = System.currentTimeMillis();
        final long data = getData();
        //this loop should be removed from function because
        //RemoveJump set test to false and modified testLoop function
        for (int i = 0; i <  data ; i++) {
            if(test) {
                ppp++;
            }
            if(test) {
                ppp++;
            }
            if(test) {
                ppp++;
            }
            if(test) {
                ppp++;
            }
            if(test) {
                ppp++;
            }
        }
        long lastTime = System.currentTimeMillis() - l;
        System.out.println(lastTime);
        System.out.println(ppp);
    }

    public static void main(String[] args) {
        RemoveJump.getInstance().testLoop();
    }
}

代码中有5个if语句。 是否可以在函数中删除这5个检查if语句? 构造函数将设置最终的布尔变量并删除跳转。 构造函数将修改testLoop函数。

但是我尝试的代码没有效果。 JIT不会修改代码吗? 为什么? 如果不行,我们能否在构造函数中修改JVM函数? 我听说过http://asm.ow2.org,这是一个用于生成或修改JVM的asm java库。


你的代码是微基准测试。运行微基准测试以使观察到的结果有意义是一项挑战,因此我建议您至少使用JMH进行测试(http://ashkrit.blogspot.ru/2013/07/how-to-write-micro-benchmark-in-java.html)。 - Andrey Breslav
你说的 JIT 没有修改哪些代码?源代码、字节码还是处理器指令? - Warren Dew
1个回答

2
事实上,JIT在循环中消除了test字段的检查。尽管看起来JIT没有足够聪明的能力在data的类型与循环索引i的类型不同时丢弃循环本身:
0x000000000222f570: inc    %ebx               ; OopMap{rbp=Oop off=178}
                                              ;*goto
                                              ; - RemoveJump::testLoop@82 (line 28)
0x000000000222f572: test   %eax,-0x20ff578(%rip)        # 0x0000000000130000
                                              ;*iload
                                              ; - RemoveJump::testLoop@20 (line 28)
                                              ;   {poll}
0x000000000222f578: movslq %ebx,%r10
0x000000000222f57b: cmp    %r14,%r10
0x000000000222f57e: jl     0x000000000222f570

如果你将getData()更改为返回int,优化将会生效,并且在结果汇编中根本不会有循环。
然而,你的测试用例无法展示优化效果,因为循环在解释器模式下开始执行,在执行过程中被编译(同时仍处于循环内部),所以即使编译后,执行仍然停留在循环内部。但是如果你多次调用testLoop()方法,你会看到进一步调用该方法时将立即打印结果,而不需要经过循环。
for (int i = 1; i <= 5; i++) {
    System.out.println("Run #" + i);
    RemoveJump.getInstance().testLoop();
}

Run #1
1897
0
Run #2
1895
0
Run #3
0
0
Run #4
0
0
Run #5
0
0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接