当从未执行的代码被注释掉时,Java程序运行得更慢 [英] Java program runs slower when code that is never executed is commented out

查看:165
本文介绍了当从未执行的代码被注释掉时,Java程序运行得更慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的一个Java程序中发现了一些奇怪的行为。我试图尽可能地删除代码,同时仍然能够复制行为。代码如下。

I observed some strange behaviour in one of my Java programs. I have tried to strip the code down as much as possible while still being able to replicate the behaviour. Code in full below.

public class StrangeBehaviour {

    static boolean recursionFlag = true;

    public static void main(String[] args) {
        long startTime = System.nanoTime();
        for (int i = 0; i < 10000; i ++) {
            functionA(6, 0);
        }
        long endTime = System.nanoTime();
        System.out.format("%.2f seconds elapsed.\n", (endTime - startTime) / 1000.0 / 1000 / 1000);
    }

    static boolean functionA(int recursionDepth, int recursionSwitch) {
        if (recursionDepth == 0) { return true; }
        return functionB(recursionDepth, recursionSwitch);
    }

    static boolean functionB(int recursionDepth, int recursionSwitch) {
        for (int i = 0; i < 16; i++) {
            if (StrangeBehaviour.recursionFlag) {
                if (recursionSwitch == 0) {
                    if (functionA(recursionDepth - 1, 1 - recursionSwitch)) return true;
                } else {
                    if (!functionA(recursionDepth - 1, 1 - recursionSwitch)) return false;
                }
            } else {
                // This block is never entered into.
                // Yet commenting out one of the lines below makes the program run slower!
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
                System.out.println("...");
            }
        }
        return false;
    }
}

我有两个函数, functionA() functionB()以递归方式相互调用。这两个函数都使用 recursionDepth 参数来控制递归的终止。 functionA()使用 recursionDepth functionB()最多一次c>不变。 functionB()使用 recursionDepth - 1 functionA() 16次C>。当使用 recursionDepth 0 functionA()时,递归终止$ c>。

I have two functions, functionA() and functionB() that call each other recursively. Both functions take a recursionDepth parameter that controls the termination of the recursion. functionA() calls functionB() a maximum of once with recursionDepth unchanged. functionB() calls functionA() 16 times with recursionDepth - 1. The recursion terminates when functionA() is called with a recursionDepth of 0.

functionB()有一个代码块,其数量为系统.out.println()来电。永远不会输入此块,因为条目由布尔recursionFlag 变量控制,该变量设置为 true 且从未更改在程序执行期间。但是,即使是其中一个 println()调用,也会导致程序运行速度变慢。在我的机器上,当所有 println()调用时,执行时间小于0.2秒,当其中一个调用被注释掉时,执行时间> 2秒。

functionB() has a code block with a number of System.out.println() calls. This block is never entered into, as entry is controlled by a boolean recursionFlag variable that is set to true and never changed during program execution. However, commenting out even one of the println() calls causes the program to run slower. On my machine, execution time is <0.2s with all the println() calls present, and >2s when one of the calls is commented out.

可能导致此行为的原因是什么?我唯一的猜测是,有一些天真的编译器优化是由与代码块长度相关的参数(或函数调用的数量等)触发的。任何进一步的见解将非常感激!

What could be causing this behaviour? My only guess is that there is some naive compiler optimisation that is being triggered by a parameter related to the length of the code block (or the number of function calls etc.). Any further insight into this will be much appreciated!

编辑:我正在使用JDK 1.8。

I'm using JDK 1.8.

推荐答案

完整答案是k5_和Tony的答案的组合。

The complete answer is a combination of k5_ and Tony's answers.

OP发布的代码省略了一个热补循环来触发HotSpot编译在做基准之前;因此,当包含print语句时,10倍(在我的计算机上)加速,结合了HotSpot花费的时间来编写字节码到CPU指令,以及CPU指令的实际运行。

The code that the OP posted omits a warmup loop to trigger HotSpot compilation before doing the benchmark; hence the 10-fold (on my computer) speedup when the print statements are included, combines both the time spent in HotSpot to compile the bytecode to CPU instructions, as well as the actual running of the CPU instructions.

如果我在定时循环之前添加一个单独的预热循环,那么print语句只有2.5倍的加速。

If I add a separate warmup loop before the timing loop, there is only a 2.5-fold speedup with the print statement.

那个表示当内联方法时(如Tony所解释的)HotSpot / JIT编译需要更长的时间以及代码的运行需要更长时间,可能是因为更糟糕的缓存或分支预测/流水线性能,如k5_所示。 / p>

That indicates that both the HotSpot/JIT compilation takes longer when the method is inlined (as Tony explained) as well as that the running of the code takes longer, probably because of worse cache or branch-prediction/pipelining performance, as k5_ showed.

public static void main(String[] args) {
    // Added the following warmup loop before the timing loop
    for (int i = 0; i < 50000; i++) {
        functionA(6, 0);
    }

    long startTime = System.nanoTime();
    for (int i = 0; i < 50000; i++) {
        functionA(6, 0);
    }
    long endTime = System.nanoTime();
    System.out.format("%.2f seconds elapsed.\n", (endTime - startTime) / 1000.0 / 1000 / 1000);
}

这篇关于当从未执行的代码被注释掉时,Java程序运行得更慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆