java - ¿Es esto un error de JVM o "comportamiento esperado"?
compiler-optimization integer-overflow (5)
Noté un comportamiento inesperado (inesperado en relación con mis expectativas personales), y me pregunto si hay algo si hay un error en la JVM o si quizás este es un caso marginal en el que no entiendo algunos de los detalles de qué exactamente se supone que suceda Supongamos que tenemos el siguiente código en un método principal por sí mismo:
int i;
int count = 0;
for(i=0; i < Integer.MAX_VALUE; i+=2){
count++;
}
System.out.println(i++);
Una expectativa ingenua sería que esto imprimirá Integer.MAX_VALUE-1
, el mayor representable int
. Sin embargo, creo que se supone que la aritmética de enteros debe "desplazarse" en Java, por lo que agregar 1 a Integer.MAX_VALUE
debería dar como resultado Integer.MIN_VALUE
. Como Integer.MIN_VALUE
aún es menor que Integer.MAX_VALUE
, el ciclo se mantendrá iterando a través de las entradas par negativas. Finalmente, volvería a 0, y este proceso debería repetirse como un ciclo infinito.
Cuando realmente ejecuto este código, obtengo resultados no deterministas. El resultado que se imprime tiende a ser del orden de medio millón, pero el valor exacto varía. Entonces, no solo termina el ciclo cuando creo que debería ser un ciclo infinito, sino que parece terminar de forma aleatoria. ¿Que esta pasando?
Supongo que esto es un error en la JVM, o hay una gran cantidad de optimización funky que hace que este comportamiento esperado. ¿Cuál es?
Error conocido. Relacionado con
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6196102
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6357214
y otros.
Creo que se consideran de baja prioridad para corregir porque no aparecen en el mundo real.
Esto es extraño Ciertamente se ve como un error en alguna parte. Obtengo los mismos resultados cada vez con el mismo código, pero los cambios triviales en el código cambian el resultado. Por ejemplo:
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);
}
}
... siempre imprime 2147483640 y verdadero
mientras que esto:
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);
}
}
siempre imprime -2147483648 y verdadero.
Muy, muy raro.
(Eso es ejecutar una VM OpenJDK 1.6 en Linux).
EDITAR: Ejecutando OpenJDK 1.7 en Windows 7, no veo el problema:
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)
Esto parece ser una optimización de bucle ya que observo el mismo resultado, pero SI también imprimo mi count
entonces el resultado cambia.
Es decir
int i;
int count = 0;
for(i=0; i < Integer.MAX_VALUE; i+=2){
count++;
}
System.out.println(count);
System.out.println(i++);
Produce 2147483638 mientras que el código original produce 457158 (o similar)
Intente agregar System.out.println(count);
Me pregunto si hay una optimización porque el recuento nunca se lee.
Editar : otra respuesta dio el enlace a los errores en el rastreador de errores de Oracle. A partir de eso:
- 6196102 en particular, menciona que hay un error de
Integer.MAX_VALUE
enInteger.MAX_VALUE
. - Java debe intentar optimizar el ciclo porque el
count
nunca se lee.
Sin embargo, es poco probable que esto ocurra en la práctica, porque:
-
Integer.MAX_VALUE
es un protector de bucle poco probable - Por lo general, los bucles hacen un trabajo que no permitiría esta optimización en primer lugar
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)
trabajando como se esperaba Bucle infinito