java - 是否可以在 java jit 上删除带有 final boolean 值的跳转?

标签 java jvm java-bytecode-asm jvm-hotspot bytecode-manipulation

我们知道有人说 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 语句? 构造函数将设置最终 boolean 变量一次并删除跳转。 Constructor会修改testLoop函数。

但是我试过的代码没有效果。 JIT 不是修改代码? 为什么 ? 如果不是,我们可以在构造函数上修改 JVM 函数吗? 我听说了http://asm.ow2.org , 用于生成或修改 JVM 的 asm java 库。

最佳答案

事实上,JIT 消除了循环中test字段的检查。尽管当 data 的类型与循环索引 i 的类型不同时,JIT 似乎不够聪明,无法丢弃循环本身:

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

关于java - 是否可以在 java jit 上删除带有 final boolean 值的跳转?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22890760/

相关文章:

java - 使用 Java 和/或 Swing 实现动态 ComboBox 的最简单方法是什么?

java - 在 Java 中,如何将字节数组转换为十六进制数字字符串,同时保持前导零?

java - "VerifyError: Expecting to find object/array on stack"在Java中使用ASM监控对象创建时?

linux - "Private_Dirty"内存在smaps中意味着什么?

java - 检查方法是否对 permgen 内存有贡献

java - ASM BasicInterpreter 非法状态异常

java - 无签名 token Java CXF 客户端

java - 编写 SQL 命令遍历 Vertex on Edges 条件

java - 使用runtime.exec()调用java方法

java - 将值存储为变量或再次调用方法更好吗?