Я наблюдал какое-то странное поведение в одной из моих программ Java. Я попытался как можно больше удалить код, сохраняя возможность повторения поведения. Код в полном объеме ниже.
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()
вызывает functionB()
максимум один раз с recursionDepth
без изменений. functionB()
вызывает functionA()
16 раз с помощью recursionDepth - 1
. Рекурсия завершается, когда functionA()
вызывается с recursionDepth
из 0
.
functionB()
имеет блок кода с числом вызовов System.out.println()
. Этот блок никогда не вводится, поскольку запись управляется переменной boolean recursionFlag
, которая установлена на true
и никогда не изменяется во время выполнения программы. Однако комментирование даже одного из вызовов println()
заставляет программу работать медленнее. На моей машине время выполнения составляет < 0,2 с всеми присутствующими вызовами println()
и > 2s, когда один из вызовов закомментирован.
Что может быть причиной такого поведения? Мое единственное предположение заключается в том, что существует некоторая наивная оптимизация компилятора, которая запускается параметром, связанным с длиной блока кода (или количеством вызовов функций и т.д.). Любое дальнейшее понимание этого будет очень оценено!
Изменить: я использую JDK 1.8.