Является ли это ошибкой 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, либо есть много фанковой оптимизации, которая делает это ожидаемым поведением. Что это?
Ответы
Ответ 1
Известная ошибка. Связано с
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6196102
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6357214
и другие.
Я думаю, что они считаются низкоприоритетными для исправления, потому что они не появляются в реальном мире.
Ответ 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)
работает как ожидалось. бесконечный цикл