Ist dies ein JVM-Fehler oder ein „erwartetes Verhalten“?


70

Ich habe ein unerwartetes Verhalten festgestellt (unerwartet im Verhältnis zu meinen persönlichen Erwartungen) und frage mich, ob etwas in der JVM fehlerhaft ist oder ob dies möglicherweise ein Randfall ist, in dem ich einige Details nicht genau verstehe soll passieren. Angenommen, wir hätten den folgenden Code in einer Hauptmethode für sich:

int i;
int count = 0;
for(i=0; i < Integer.MAX_VALUE; i+=2){
  count++;
}
System.out.println(i++);

Eine naive Erwartung wäre, dass dies gedruckt wird Integer.MAX_VALUE-1, die größte sogar darstellbar int. Ich glaube jedoch, dass Ganzzahlarithmetik in Java "rollover" soll, daher sollte das Hinzufügen von 1 zu Integer.MAX_VALUEführen Integer.MIN_VALUE. Da Integer.MIN_VALUEimmer noch kleiner als ist Integer.MAX_VALUE, würde die Schleife die negativen geraden Ints weiter durchlaufen. Schließlich würde es auf 0 zurückkehren, und dieser Vorgang sollte sich als Endlosschleife wiederholen.

Wenn ich diesen Code tatsächlich ausführe, erhalte ich nicht deterministische Ergebnisse. Das Ergebnis, das gedruckt wird, liegt in der Regel in der Größenordnung von einer halben Million, aber der genaue Wert variiert. Die Schleife endet also nicht nur, wenn ich glaube, dass es eine Endlosschleife sein sollte, sondern sie scheint zufällig zu enden. Was ist los?

Ich vermute, dass dies entweder ein Fehler in der JVM ist oder dass eine Menge funky Optimierungen stattfinden, die dieses erwartete Verhalten bewirken. Welches ist es?


Ist das alles, was in Ihrer Hauptmethode enthalten ist?
Jon Skeet

@ Michael: Nur zu überprüfen, ob es kein funky Threading gibt. Auf meinem Computer wird immer 2147483640 ausgedruckt, aber das ist immer noch unerwartet.
Jon Skeet

2
Ich habe es dreimal mit unterschiedlichen Ergebnissen zwischen 300.000 und 500.000 versucht - es sieht also so aus, als wäre es VM-spezifisch (Build 1.6.0_24-b07, 32-Bit-Linux)
Matthew Gilliard

Das Programm wird unter 32-Bit-Windows XP mit HotSpot 1.6.0_24
Jeremy

1
Java überrascht mich immer wieder. +1 zum OP und +1 zur Antwort, die mit den Oracle / Sung-Fehlern verknüpft ist. Mein letzter Favorit war dieser: stackoverflow.com/questions/4949057 :)
SyntaxT3rr0r

Antworten:



15

Das ist bizarr. Es sieht auf jeden Fall irgendwo wie ein Käfer aus. Ich erhalte jedes Mal die gleichen Ergebnisse mit dem gleichen Code, aber geringfügige Änderungen am Code ändern das Ergebnis. Zum Beispiel:

public class Test {
  public static void main(String[] args) {
    int i;
    int count = 0;
    for (i = 0; i < Integer.MAX_VALUE; i+=2) {
      count++;
    }
    System.out.println(i);
    System.out.println(i < Integer.MAX_VALUE);
  }
}

... druckt immer 2147483640 und wahr

in der Erwägung, dass dies:

public class Test {
  public static void main(String[] args) {
    int i;
    for (i = 0; i < Integer.MAX_VALUE; i+=2) {
    }
    System.out.println(i);
    System.out.println(i < Integer.MAX_VALUE);
  }
}

druckt immer -2147483648 und true.

Sehr, sehr komisch.

(Damit wird eine OpenJDK 1.6-VM unter Linux ausgeführt.)

BEARBEITEN: Wenn Sie OpenJDK 1.7 unter Windows 7 ausführen, sehe ich das Problem nicht:

java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b78)
Java HotSpot(TM) Client VM (build 17.0-b05, mixed mode, sharing)

4

Versuchen Sie es hinzuzufügen System.out.println(count);

Ich frage mich, ob eine Optimierung stattfindet, weil die Anzahl nie gelesen wird.

Bearbeiten - Eine andere Antwort gab den Link zu Fehlern im Fehler-Tracker von Oracle. Daraus schöpfen:

  • 6196102 erwähnt insbesondere, dass es einen Kanonisierungsfehler gibt, wenn Integer.MAX_VALUEes darum geht.
  • Java muss versuchen, die Schleife zu optimieren, da sie countnie gelesen wird.

In der Praxis ist dies jedoch unwahrscheinlich, da:

  • Integer.MAX_VALUE ist ein unwahrscheinlicher Schleifenschutz
  • Normalerweise funktionieren Schleifen, die diese Optimierung überhaupt nicht zulassen

Dies macht meine Testläufe zumindest konsistent. Es handelt sich also um ein Optimierungsproblem?
Matthew Gilliard

2

Dies scheint eine Schleifenoptimierung zu sein, da ich das gleiche Ergebnis beobachte, aber wenn ich auch drucke, countändert sich das Ergebnis.

Dh

    int i;
    int count = 0;
    for(i=0; i < Integer.MAX_VALUE; i+=2){
      count++;
    }
    System.out.println(count);
    System.out.println(i++);

Erzeugt 2147483638, während der ursprüngliche Code 457158 (oder ähnliches) erzeugt.


0
java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Java HotSpot(TM) Client VM (build 17.1-b03, mixed mode, sharing)

wie erwartet arbeiten. Endlosschleife

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.