Это ошибка JVM или «ожидаемое поведение»? - PullRequest
70 голосов
/ 03 марта 2011

Я заметил какое-то неожиданное поведение (неожиданное относительно моих личных ожиданий), и мне интересно, есть ли что-то, если есть ошибка в JVM или, возможно, это незначительный случай, когда я не понимаю некоторые детали о том, что именно должно произойти. Предположим, что в основном методе у нас был следующий код:

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

Наивным ожиданием было бы то, что это напечатало бы Integer.MAX_VALUE-1, самое большое четное представимое int. Тем не менее, я считаю, что целочисленная арифметика должна «переворачиваться» в Java, поэтому добавление 1 к Integer.MAX_VALUE должно привести к Integer.MIN_VALUE. Поскольку Integer.MIN_VALUE по-прежнему меньше Integer.MAX_VALUE, цикл будет повторять отрицательные четные числа. В конце концов он вернется к 0, и этот процесс должен повториться как бесконечный цикл.

Когда я на самом деле запускаю этот код, я получаю недетерминированные результаты. Результат печати обычно составляет порядка полумиллиона, но точное значение варьируется. Таким образом, цикл не только заканчивается, когда я считаю, что это должен быть бесконечный цикл, но, кажется, он прерывается случайно. Что происходит?

Я предполагаю, что это либо ошибка в JVM, либо происходит много лишних оптимизаций, приводящих к такому ожидаемому поведению. Что это?

Ответы [ 5 ]

48 голосов
/ 03 марта 2011

Известная ошибка.Относится к

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6196102

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6357214

и другим.

Я думаю, что они считаются низко приоритетными для исправления, потому что они нев реальном мире.

15 голосов
/ 03 марта 2011

Это странно.Это, конечно, где-то похоже на ошибку.Я получаю одинаковые результаты каждый раз с одним и тем же кодом, но тривиальные изменения в коде меняют результат.Например:

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);
  }
}

... всегда печатает 2147483640 и true

, тогда как это:

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);
  }
}

всегда печатает -2147483648 и true.

Очень, очень странно.

(Это работает на виртуальной машине OpenJDK 1.6 в Linux.)

РЕДАКТИРОВАТЬ: Запуск OpenJDK 1.7 в Windows 7, я не вижу проблемы:

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 голосов
/ 03 марта 2011

Попробуйте добавить System.out.println(count);

Интересно, происходит ли оптимизация, потому что отсчет никогда не читается.

Редактировать - другой ответ дал ссылку на ошибки в системе отслеживания ошибок Oracle. Рисунок из этого:

  • 6196102 , в частности, упоминается, что существует ошибка канонизации, касающаяся Integer.MAX_VALUE.
  • Java должна пытаться оптимизировать цикл, потому что count никогда не читается из.

Однако на практике это вряд ли произойдет, потому что:

  • Integer.MAX_VALUE маловероятный защитный кожух
  • Обычно работают циклы, которые не позволяют эту оптимизацию вообще
2 голосов
/ 03 марта 2011

Это похоже на циклическую оптимизацию, так как я наблюдаю тот же результат, но если я также распечатаю count, то результат меняется.

Т.е.

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

Производит 2147483638, в то время какИсходный код выдает 457158 (или аналогичный)

0 голосов
/ 03 марта 2011
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)

работает как положено.бесконечный цикл

...