Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当JVM不执行代码优化的方法时_Java_Jvm - Fatal编程技术网

Java 当JVM不执行代码优化的方法时

Java 当JVM不执行代码优化的方法时,java,jvm,Java,Jvm,在阅读Scott Oaks的《Java性能》一书时,我遇到了一段代码,其中说Java 7或8 JVM足够聪明,可以跳过for循环中提供的计算部分,因为将来不会使用结果(微基准标记) 书中提到的代码: public void doTest() { // Main Loop double l; long then = System.currentTimeMillis(); for (int i = 0; i < nLoops; i++) { l

在阅读Scott Oaks的《Java性能》一书时,我遇到了一段代码,其中说Java 7或8 JVM足够聪明,可以跳过for循环中提供的计算部分,因为将来不会使用结果(微基准标记)

书中提到的代码:

public void doTest() {
    // Main Loop
    double l;
    long then = System.currentTimeMillis();

    for (int i = 0; i < nLoops; i++) {
        l = fibImpl1(50);
    }
    long now = System.currentTimeMillis();
    System.out.println("Elapsed time: " + (now - then));
}

private double fibImpl1(int n) {
   if (n < 0) throw new IllegalArgumentException("Must be > 0");
   if (n == 0) return 0d;
   if (n == 1) return 1d;
   double d = fibImpl1(n - 2) + fibImpl(n - 1);
   if (Double.isInfinite(d)) throw new ArithmeticException("Overflow");
  return d;
} 
为了验证这一点,我尝试了一个代码,但运行时间计算并没有反映上述理论

我的代码版本:

    public class APSum {

    public static void main(String[] args) {

        long then = System.currentTimeMillis();
        ArithmeticProgression.sum(500000000);
        long now = System.currentTimeMillis();
        System.out.println("Elapsed time: " + (now - then));
    }
}

    class ArithmeticProgression{
    public static double sum(int i){
        double sum=0;
        for(int index=0; index<=i; index++){
            sum = sum + (double)index;
        }
        return sum;
    }
}
public-class-APSum{
公共静态void main(字符串[]args){
long then=System.currentTimeMillis();
算术级数和(500000000);
long now=System.currentTimeMillis();
System.out.println(“经过的时间:+(现在-然后));
}
}
类算术级数{
公共静态双和(int i){
双和=0;

对于(int index=0;index现代JVM太复杂了,需要进行各种优化。如果您试图测量一些小代码,如果没有对JVM正在做的事情的非常详细的了解,要正确地执行它就非常复杂。死代码消除(DCE)是一种经常导致微基准出错的优化

有两个经典错误(阅读更多关于常见错误和错误的信息):

  • 因为编译的最小单元是方法,所以基准测试必须有多个主方法
  • 没有预热迭代。始终包括一个预热阶段,该阶段将一直运行测试内核,足以在计时阶段之前触发所有初始化和编译
修正后,我们的基准如下所示:

    public class APSum {

    public static void main(String[] args) {
        for (int i = 0; i < 5000; i++) {
            test();
        }
    }

    private static void test() {
        long then = System.currentTimeMillis();
        sum(5000000);
        long now = System.currentTimeMillis();
        System.out.println("Elapsed time: " + (now - then));
    }

    public static double sum(int i){
        double sum=0;
        for(int index=0; index<=i; index++){
            sum = sum + (double)index;
        }
        return sum;
    }
    }
编译器未能内联方法APSum::sum,原因是。事实上,虽然在基准测试中(尤其是在微基准测试中)经常触发,但在应用程序代码中触发的频率较低。为了获得正确的结果,我们必须添加更多预热迭代:

    public class APSum {

    public static void main(String[] args) {
        for (int i = 0; i < 10000; i++) {
            test();
        }
    }

    private static void test() {
        long then = System.currentTimeMillis();
        sum(5000000);
        long now = System.currentTimeMillis();
        System.out.println("Elapsed time: " + (now - then));
    }

    public static double sum(int i){
        double sum=0;
        for(int index=0; index<=i; index++){
            sum = sum + (double)index;
        }
        return sum;
    }
    }

你试过书中的代码了吗?编译器是聪明的,但它不是无限聪明的。因为没有使用结果,它可以扔掉一些东西的程度是有限的。你的例子可能太复杂了,所以编译器不会扔掉它。你在混淆概念。据我所知,java compi将源代码转换为字节码(类文件)的ler它非常愚蠢。与其他编译器(如gcc)相比,它没有做任何重要的优化。换句话说:编译器构造函数知道优化的许多概念中,只有很少的概念被应用。如果Java7、8改变了这一点,我一定错过了它……但发生的事情是,即时编译器不断地优化在运行时编写代码;请参见此处示例。此外,JIT优化高度依赖于平台。因此,不要期望同一代码在不同平台上的行为一致。您可能正在研究一种专门的JVM优化,因为执行优化的不是编译器,而是JIT。Javac和您的Java一样愚蠢编译器的get。由于
OSR
,内联失败?为什么?内联不应该是对OSR的补充吗?@Eugene(来源):“如果我们使用C1编译一个分析方法,并且已知被调用方在C2版本中有OSRed,请不要内联。”
   @ 0   java.lang.System::currentTimeMillis (0 bytes)   intrinsic
   @ 6   edu.jvm.runtime.APSum::sum (22 bytes)   inlining prohibited by policy
   @ 10   java.lang.System::currentTimeMillis (0 bytes)   intrinsic
    public class APSum {

    public static void main(String[] args) {
        for (int i = 0; i < 10000; i++) {
            test();
        }
    }

    private static void test() {
        long then = System.currentTimeMillis();
        sum(5000000);
        long now = System.currentTimeMillis();
        System.out.println("Elapsed time: " + (now - then));
    }

    public static double sum(int i){
        double sum=0;
        for(int index=0; index<=i; index++){
            sum = sum + (double)index;
        }
        return sum;
    }
    }
  Elapsed time: 5
  Elapsed time: 4
  Elapsed time: 5

    @ 0   java.lang.System::currentTimeMillis (0 bytes)   (intrinsic)
    @ 6   edu.jvm.runtime.APSum::sum (22 bytes)   inline (hot)
    @ 10   java.lang.System::currentTimeMillis (0 bytes)   (intrinsic)

  Elapsed time: 0
  Elapsed time: 0
  Elapsed time: 0