J'ai observé un comportement étrange dans l'un de mes programmes Java. J'ai essayé de dépouiller le code autant que possible tout en étant capable de reproduire le comportement. Code complet ci-dessous.
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;
}
}
J'ai deux fonctions, functionA()
y functionB()
qui s'appellent mutuellement de manière récursive. Les deux fonctions prennent un recursionDepth
qui contrôle la fin de la récursion. functionA()
appelle functionB()
une fois au maximum avec recursionDepth
inchangé. functionB()
appelle functionA()
16 fois avec recursionDepth - 1
. La récursion se termine lorsque functionA()
est appelé avec un recursionDepth
de 0
.
functionB()
a un bloc de code avec un certain nombre de System.out.println()
appels. Ce bloc n'est jamais pénétré, car l'entrée est contrôlée par un système d'alarme. boolean recursionFlag
qui a pour valeur true
et n'a jamais été modifié pendant l'exécution du programme. Cependant, le fait de commenter ne serait-ce qu'un seul des println()
entraîne un ralentissement de l'exécution du programme. Sur ma machine, le temps d'exécution est <0,2s avec tous les println()
présents, et >2s lorsque l'un des appels est commenté.
Quelle pourrait être la cause de ce comportement ? Ma seule hypothèse est qu'il y a une optimisation naïve du compilateur qui est déclenchée par un paramètre lié à la longueur du bloc de code (ou au nombre d'appels de fonction, etc.). Je vous serais reconnaissant de bien vouloir m'éclairer sur ce point !
Modification : j'utilise le JDK 1.8.