Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/311.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.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 为什么要在这个相同的代码中减速?_Java - Fatal编程技术网

Java 为什么要在这个相同的代码中减速?

Java 为什么要在这个相同的代码中减速?,java,Java,我试图测量执行此循环的时间: for (boolean t : test) { if (!t) ++count; } 结果不一致。最终,我通过以下代码获得了一致的结果: public class Test { public static void main(String[] args) { int size = 100; boolean[] test = new boolean[10_000_000]; java.

我试图测量执行此循环的时间:

for (boolean t : test) {
    if (!t)
        ++count;
}
结果不一致。最终,我通过以下代码获得了一致的结果:

public class Test {
    public static void main(String[] args) {
        int size = 100;
        boolean[] test = new boolean[10_000_000];
        java.util.Random r = new java.util.Random();
        for (int n = 0; n < 10_000_000; ++n)
            test[n] = !r.nextBoolean();

        int expected = 0;
        long acumulated = 0;
        for (int repeat = -1; repeat < size; ++repeat) {
            int count = 0;
            long start = System.currentTimeMillis();
            for (boolean t : test) {
                if (!t)
                    ++count;
            }
            long end = System.currentTimeMillis();
            if (repeat != -1)  // First run does not count, VM warming up
                acumulated += end - start;
            else                  // Use count to avoid compiler or JVM
                expected = count; //optimization of inner loop
            if ( count!=expected )
                throw new Error("Tests don't run same ammount of times");
        }
        float average = (float) acumulated / size;
        System.out.println("1st test : " + average);

        int expectedBis = 0;
        acumulated = 0;
        if ( "reassign".equals(args[0])) {
            for (int n = 0; n < 10_000_000; ++n)
                test[n] = test[n];
        }
        for (int repeat = -1; repeat < size; ++repeat) {
            int count = 0;
            long start = System.currentTimeMillis();
            for (boolean t : test) {
                if (!t)
                    ++count;
            }
            long end = System.currentTimeMillis();
            if (repeat != -1)  // First run does not count, VM warming up
                acumulated += end - start;
            else                     // Use count to avoid compiler or JVM
                expectedBis = count; //optimization of inner loop
            if ( count!=expected || count!=expectedBis)
                throw new Error("Tests don't run same ammount of times");
        }
        average = (float) acumulated / size;
        System.out.println("2nd test : " + average);
    }

}
区别在于在第二次测试之前是否执行此循环

for (int n = 0; n < 10_000_000; ++n)
    test[n] = test[n];
for(int n=0;n<10\u 000\u 000;++n)
试验[n]=试验[n];
为什么??为什么重新分配会导致之后的循环花费两倍的时间?

正确地分析是很困难的…

我想把它作为一个评论,但我的声誉太低了,所以必须把它作为一个答案添加进去

我用你的代码创建了一个jar,并运行了好几次。我还将代码复制到C#,并在.NET运行时运行它

Java和C#都显示相同的精确时间,有无“重新分配”循环

如果将循环更改为

 if ( "reassign".equals(args[0])) {
        for (int n = 0; n < 5_000_000; ++n)
            test[n] = test[n];
    }
if(“重新分配”.equals(args[0])){
对于(int n=0;n<5_000_000;++n)
试验[n]=试验[n];
}

Marko Topolniks和rossum的评论让我走上了正确的方向。
这是一个JIT编译器问题。
如果禁用JIT编译器,则会得到以下结果:

$ java -jar Test.jar -Djava.compiler=NONE noreassign  
1st test : 19.23  
2nd test : 19.33  
$ java -jar Test.jar -Djava.compiler=NONE reassign  
1st test : 19.23  
2nd test : 19.32  
一旦JIT编译器停用,奇怪的减速就会消失。
至于为什么JIT编译器会导致这种行为。。。这超出了我的技能和知识范围。
但这并不像Marius Dornean的测试所示,在所有JVM中都会发生

“至于为什么JIT编译器会导致这种行为……这超出了我的技能和知识。”

三个基本事实:

  • JIT编译后代码运行更快

  • JIT编译是在一段代码运行一段时间后触发的。(一位的长度受JVM平台和命令行选项的影响。)

  • JIT编译需要时间

  • 在您的例子中,当您在测试1和测试2之间插入大赋值循环时,您很可能正在移动触发JIT编译的时间点。。。从测试2期间到两次测试之间

    在这种情况下解决这个问题的简单方法是将
    main
    的主体放入一个循环中,并重复运行它。然后丢弃前几次运行中的异常结果

    (关闭JIT编译不是一个好的答案。通常,JIT编译后代码的性能特征将指示实际应用程序的执行方式…)

    通过将编译器设置为“无”,可以禁用JIT编译,从而将其从等式中去掉


    当人们试图手工编写微基准测试时,这种异常现象很常见。阅读以下问答:


    最好开始研究程序的JIT编译代码,因为这是唯一有机会找到答案的地方。您的额外循环可能会将部分或全部test[]数组拉入快速内存,因此它的执行更加一致。它还允许JIT编译器进行一些优化。通常,如果您想要精确的计时,请在开始计时循环之前运行该进程几百/千次。这样可以避免任何启动影响,并且系统处于稳定状态。@rossum如果重新分配循环将test[]拉入快速内存,我希望第二个测试运行得更快。JIT优化也是如此。但我得到了相反的结果。我还尝试将预热非测量回路从1增加到1000,但仍然得到相同的结果。但是是的,这可能是JIT编译器的问题。我得到了第一个测试:24.01第二个测试:38.06和“重新分配”,我得到了第一个测试:24.0第二个测试:23.97和“noreassign”。同样的结果。必须是特定于我的JVM、操作系统和/或机器的东西。我预测这不会有什么区别。
    $ java -jar Test.jar -Djava.compiler=NONE noreassign  
    1st test : 19.23  
    2nd test : 19.33  
    $ java -jar Test.jar -Djava.compiler=NONE reassign  
    1st test : 19.23  
    2nd test : 19.32