Hallo zusammen,
im Folgenden zeige ich Euch den Quelltext zu einem Mini-Programm, das mir ziemlich rätselhaft vorkommt:
Kurze Erklärung des Source:
Im Prinzip wird einfach eine Schleife von START bis END durchlaufen und sodann die Anzahl der Durchläufe ausgegeben - im Allgemeinen kein Problem.
Da nun aber END auf den maximal möglichen Wert eines 4Byte signed Integer gesetzt wird und die Schleife erst bei i > END abbricht (da i <= END), kommt es zu einer Endlos-Schleife. Völlig korrekt - der Integer i muss theoretisch im "letzten" Schleifendurchlauf um 1 größer als der maximal mögliche Integer sein, was nicht möglich ist. Stattdessen wird i klammheimlich umgebogen auf Integer.MIN_VALUE. Daher wird die Schleife nie beendet.
So auch das von mir erwartete Ergebnis.
Das Problem:
Ich habe die Start- und Endwerte explizit als Konstanten deklariert, auch wenn das eigentlich nicht nötig wäre, um eine Endlosschleife zu erzeugen.
Mit jre6 wie auch mit java-6-openjdk als Standard-VM funktioniert das Programm auch wie erwartet (Endlosschleife).
Aaaber: Nun entferne ich den final-Modifizierer von END. Dadurch sollte logischer Weise (nach meiner Logik
) das Ergebnis nicht verändert werden. Für die sun/oracle-Variante stimmt das auch. Unter Verwendung der freien Variante wird nun jedoch die Zahl "101" ausgegeben - die Schleife terminiert also anscheinend.
Warum genau nun via openjdk die Schleife terminiert ist mir ein Rätsel. Irgendwas muss intern anders laufen, sobald ich den final-Modifizierer entferne. Allerdings sollte das nach meinem Verständnis keine Auswirkung haben; die Zählvariable i bleibt ja trotzdem gleich.
Daraufhin habe ich mir Interesse halber den Bytecode der beiden Quelltexte via javap "disassembled". Die Ausgaben habe ich als txt-Datei diesem Thread angehängt. Aber auch da sehe ich nichts, was die Ursache der Änderung sein könnte.
Die eigentliche Frage:
Hat von Euch einer eine Ahnung oder Vermutung, was hier im openjdk anders behandelt wird (wenn das überhaupt die Ursache ist), sodass obiges Problem auftritt (evtl. irgendeine Art von automatischer "Optimierung")?
Theoretisch wäre das Problem gar nicht mal so wichtig, da es sich um einen reinen corner-case handelt und man in solchen Randfällen sicher keine Integer-Zählvariable nutzen würde. Aber trotzdem interessiert es mich einfach, warum die verschiedenen VMs in diesem Punkt völlig anders reagieren.
Entweder sehe ich vor lauter Bäumen den Wald nicht mehr oder es ist wirklich ein sehr komisches Problem.
Mein System:
Es sollte eigentlich dabei weniger eine Rolle spielen, aber der Vollständigkeit halber:
System mit openjdk
Referenz-System ohne openjdk
Falls ich noch etwas vergessen habe, einfach melden.
Vielen Dank im Voraus, dass Ihr schonmal bis hier hin gelesen habt.
Und noch ein größeres Dankeschön für Hilfe!
viele Grüße,
Sn0wm4n
im Folgenden zeige ich Euch den Quelltext zu einem Mini-Programm, das mir ziemlich rätselhaft vorkommt:
Java:
public class InfiniteLoop {
public static final int END = Integer.MAX_VALUE;
public static final int START = END - 100;
public static void main (String[] args) {
int count = 0;
for (int i = START; i <= END; i++) {
count++;
}
System.out.println(count);
}
}
Kurze Erklärung des Source:
Im Prinzip wird einfach eine Schleife von START bis END durchlaufen und sodann die Anzahl der Durchläufe ausgegeben - im Allgemeinen kein Problem.
Da nun aber END auf den maximal möglichen Wert eines 4Byte signed Integer gesetzt wird und die Schleife erst bei i > END abbricht (da i <= END), kommt es zu einer Endlos-Schleife. Völlig korrekt - der Integer i muss theoretisch im "letzten" Schleifendurchlauf um 1 größer als der maximal mögliche Integer sein, was nicht möglich ist. Stattdessen wird i klammheimlich umgebogen auf Integer.MIN_VALUE. Daher wird die Schleife nie beendet.
So auch das von mir erwartete Ergebnis.
Das Problem:
Ich habe die Start- und Endwerte explizit als Konstanten deklariert, auch wenn das eigentlich nicht nötig wäre, um eine Endlosschleife zu erzeugen.
Mit jre6 wie auch mit java-6-openjdk als Standard-VM funktioniert das Programm auch wie erwartet (Endlosschleife).
Aaaber: Nun entferne ich den final-Modifizierer von END. Dadurch sollte logischer Weise (nach meiner Logik
Warum genau nun via openjdk die Schleife terminiert ist mir ein Rätsel. Irgendwas muss intern anders laufen, sobald ich den final-Modifizierer entferne. Allerdings sollte das nach meinem Verständnis keine Auswirkung haben; die Zählvariable i bleibt ja trotzdem gleich.
Daraufhin habe ich mir Interesse halber den Bytecode der beiden Quelltexte via javap "disassembled". Die Ausgaben habe ich als txt-Datei diesem Thread angehängt. Aber auch da sehe ich nichts, was die Ursache der Änderung sein könnte.
Die eigentliche Frage:
Hat von Euch einer eine Ahnung oder Vermutung, was hier im openjdk anders behandelt wird (wenn das überhaupt die Ursache ist), sodass obiges Problem auftritt (evtl. irgendeine Art von automatischer "Optimierung")?
Theoretisch wäre das Problem gar nicht mal so wichtig, da es sich um einen reinen corner-case handelt und man in solchen Randfällen sicher keine Integer-Zählvariable nutzen würde. Aber trotzdem interessiert es mich einfach, warum die verschiedenen VMs in diesem Punkt völlig anders reagieren.
Entweder sehe ich vor lauter Bäumen den Wald nicht mehr oder es ist wirklich ein sehr komisches Problem.
Mein System:
Es sollte eigentlich dabei weniger eine Rolle spielen, aber der Vollständigkeit halber:
System mit openjdk
- 32-bit Unix (Ubuntu 10.04)
- Eclipse 1.2.2.x zur Entwicklung
Referenz-System ohne openjdk
- 64-bit Windows (Win7)
- Eclipse 1.2.2.x zur Entwicklung
Falls ich noch etwas vergessen habe, einfach melden.
Vielen Dank im Voraus, dass Ihr schonmal bis hier hin gelesen habt.
Und noch ein größeres Dankeschön für Hilfe!
viele Grüße,
Sn0wm4n