Java JVM优化是如何基于假设的?

Java JVM优化是如何基于假设的?,java,jvm,jit,Java,Jvm,Jit,在第12.3.3节“不现实的代码路径采样”中,《Java并发性实践》一书说: 在某些情况下,JVM 可能会基于可能只是暂时正确的假设进行优化,然后在不正确的情况下通过使编译的代码无效来撤销这些假设 我无法理解上述陈述 这些JVM假设是什么 JVM如何知道这些假设是真是假 如果假设不真实,是否会影响我数据的正确性 您引用的声明有一个脚注,其中给出了一个示例: 例如,如果当前加载的类没有覆盖该方法,JVM可以使用单态调用转换将虚拟方法调用转换为直接方法调用,但是如果随后加载了覆盖该方法的类,JVM将

在第12.3.3节“不现实的代码路径采样”中,《Java并发性实践》一书说:

在某些情况下,JVM 可能会基于可能只是暂时正确的假设进行优化,然后在不正确的情况下通过使编译的代码无效来撤销这些假设

我无法理解上述陈述

  • 这些JVM假设是什么
  • JVM如何知道这些假设是真是假
  • 如果假设不真实,是否会影响我数据的正确性

  • 您引用的声明有一个脚注,其中给出了一个示例:

    例如,如果当前加载的类没有覆盖该方法,JVM可以使用单态调用转换将虚拟方法调用转换为直接方法调用,但是如果随后加载了覆盖该方法的类,JVM将使编译后的代码无效

    这里的细节非常非常复杂。因此,下面是一个极端过分简化的例子

    假设您有一个界面:

     interface Adder { int add(int x); }
    
    该方法应该向
    x
    添加一个值,并返回结果。现在假设有一个程序使用这个类的实现:

    class OneAdder implements Adder { 
        int add(int x) {
            return x+1;
        }
    }
    
    class Example {
    
        void run() {
            OneAdder a1 = new OneAdder();
            int result = compute(a1);
            System.out.println(result);
        }
    
        private int compute(Adder a) {
            int sum = 0;
            for (int i=0; i<100; i++) {
                sum = a.add(sum);
            }
            return sum;
        }
    }
    
    原则上,即使是这个

    private int compute(Adder a) {
        return 100;
    }
    
    但是JVM也可以在运行时加载类。因此,可能有这样一种情况,即这种优化已经完成,稍后JVM将加载如下类:

    class TwoAdder implements Adder { 
        int add(int x) {
            return x+2;
        }
    }
    
    现在,对
    compute
    方法进行的优化可能会变得“无效”,因为不清楚它是用
    OneAdder
    还是用
    TwoAdder
    调用的。在这种情况下,必须撤消优化

    这应该回答你问题的1.

    关于2.:当然,JVM会跟踪所有已经完成的优化。它知道它内联了
    add
    方法,前提是该方法只有一个实现。当它找到此方法的另一个实现时,它必须撤消优化

    关于3.:在假设为真时进行优化。当它们变得不真实时,优化将撤消。因此,这不会影响程序的正确性


    更新:


    同样,上面的例子非常简单,参考了书中的脚注。有关JVM优化技术的更多信息,请参阅。具体地说,可以认为主要是基于“假设”——即,基于迄今为止收集到的分析数据做出的假设。

    您引用的声明有一个脚注,其中给出了一个示例:

    例如,如果当前加载的类没有覆盖该方法,JVM可以使用单态调用转换将虚拟方法调用转换为直接方法调用,但是如果随后加载了覆盖该方法的类,JVM将使编译后的代码无效

    这里的细节非常非常复杂。因此,下面是一个极端过分简化的例子

    假设您有一个界面:

     interface Adder { int add(int x); }
    
    该方法应该向
    x
    添加一个值,并返回结果。现在假设有一个程序使用这个类的实现:

    class OneAdder implements Adder { 
        int add(int x) {
            return x+1;
        }
    }
    
    class Example {
    
        void run() {
            OneAdder a1 = new OneAdder();
            int result = compute(a1);
            System.out.println(result);
        }
    
        private int compute(Adder a) {
            int sum = 0;
            for (int i=0; i<100; i++) {
                sum = a.add(sum);
            }
            return sum;
        }
    }
    
    原则上,即使是这个

    private int compute(Adder a) {
        return 100;
    }
    
    但是JVM也可以在运行时加载类。因此,可能有这样一种情况,即这种优化已经完成,稍后JVM将加载如下类:

    class TwoAdder implements Adder { 
        int add(int x) {
            return x+2;
        }
    }
    
    现在,对
    compute
    方法进行的优化可能会变得“无效”,因为不清楚它是用
    OneAdder
    还是用
    TwoAdder
    调用的。在这种情况下,必须撤消优化

    这应该回答你问题的1.

    关于2.:当然,JVM会跟踪所有已经完成的优化。它知道它内联了
    add
    方法,前提是该方法只有一个实现。当它找到此方法的另一个实现时,它必须撤消优化

    关于3.:在假设为真时进行优化。当它们变得不真实时,优化将撤消。因此,这不会影响程序的正确性


    更新:


    同样,上面的例子非常简单,参考了书中的脚注。有关JVM优化技术的更多信息,请参阅。具体地说,这些假设可能主要基于“假设”——也就是说,基于迄今为止收集到的分析数据所做的假设。

    根据引用的文本上下文,本书的这一部分实际上是在讨论使用真实文本数据(输入)的重要性当您进行性能测试时

    你的问题:


    这些JVM假设是什么

    我认为课文讨论了两件事:

    • 一方面,它似乎在谈论基于代码路径度量的优化。例如,
      if
      语句的“then”或“else”分支更有可能被执行。这确实会导致生成不同的代码,并且如果初始测量不正确,很容易产生次优代码

    • 另一方面,它似乎也在谈论可能被证明无效的优化。例如,在某个时间点,JVM可能只加载了给定接口方法的一个实现。看到这个问题,优化器可能会决定简化调用序列,以避免多态方法调度。(本书中用于此目的的术语