Является ли это ошибкой JVM или "ожидаемым поведением"?

Я заметил какое-то неожиданное поведение (неожиданное по сравнению с моими личными ожиданиями), и мне интересно, если что-то, если в 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, цикл будет продолжать итерацию через отрицательные четные int. В конце концов, он вернется к 0, и этот процесс должен повторяться как бесконечный цикл.

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

Моя догадка заключается в том, что это либо ошибка в JVM, либо есть много фанковой оптимизации, которая делает это ожидаемым поведением. Что это?

Ответ 2

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

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 VM на Linux.)

EDIT: запуск 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)

Ответ 3

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

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

Изменить - еще один ответ дал ссылку на ошибки в Oracle bug tracker. Опираясь на это:

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

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

  • Integer.MAX_VALUE - маловероятный защитник цикла
  • Обычно циклы выполняют работу, которая не позволяла бы эту оптимизацию в первую очередь

Ответ 4

Кажется, это оптимизация цикла, поскольку я наблюдаю тот же результат, но ЕСЛИ я также распечатываю 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 (или аналогичный)

Ответ 5

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)

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