Подтвердить что ты не робот

Ошибочные for-loops в Java?

Я заметил ошибочное поведение, выполняющее следующий java-код:

public class Prototype {
  public static void main(String[] args) {
    final int start = Integer.MAX_VALUE/2;
    final int end = Integer.MAX_VALUE;
    {
      long b = 0;
      for (int i = start; i < end; i++) {
        b++;
      }
      System.out.println(b);
    }
    {
      long b = 0;
      for (int i = start; i < end; i++) {
        b++;
      }
      System.out.println(b);
    }
  }
}

Обе петли делают точно то же самое. Тем не менее, вторая выводит недетерминированное ошибочное значение. Я запускаю код в Linux с помощью Version:

java version "1.6.0_25"
Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.0-b11, mixed mode)

Пример вывода:

1073741811
141312

Можете ли вы воспроизвести его? Это ошибка?

Изменить: Странно

final int end = Integer.MAX_VALUE - 1;

отлично работает.

4b9b3361

Ответ 1

Я могу воспроизвести его с помощью файла .class, созданного Eclipse, но не при компиляции в командной строке с помощью javac.

Созданный байт-код отличается:

javac вывод

public static void main(java.lang.String[]);
  Code:
   0:   lconst_0
   1:   lstore_3
   2:   ldc #2; //int 1073741823
   4:   istore  5
   6:   iload   5
   8:   ldc #3; //int 2147483647
   10:  if_icmpge   23
   13:  lload_3
   14:  lconst_1
   15:  ladd
   16:  lstore_3
   17:  iinc    5, 1
   20:  goto    6
   23:  getstatic   #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   26:  lload_3
   27:  invokevirtual   #5; //Method java/io/PrintStream.println:(J)V
   30:  lconst_0
   31:  lstore_3
   32:  ldc #2; //int 1073741823
   34:  istore  5
   36:  iload   5
   38:  ldc #3; //int 2147483647
   40:  if_icmpge   53
   43:  lload_3
   44:  lconst_1
   45:  ladd
   46:  lstore_3
   47:  iinc    5, 1
   50:  goto    36
   53:  getstatic   #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   56:  lload_3
   57:  invokevirtual   #5; //Method java/io/PrintStream.println:(J)V
   60:  return

Для чего-то более легкого для чтения, вот результат Grimp, созданный Soot:

    java.lang.String[] r0;
    long l0, l2;
    int i1, i3;

    r0 := @parameter0;
    l0 = 0L;
    i1 = 1073741823;

 label0:
    if i1 >= 2147483647 goto label1;

    l0 = l0 + 1L;
    i1 = i1 + 1;
    goto label0;

 label1:
    java.lang.System.out.println(l0);
    l2 = 0L;
    i3 = 1073741823;

 label2:
    if i3 >= 2147483647 goto label3;

    l2 = l2 + 1L;
    i3 = i3 + 1;
    goto label2;

 label3:
    java.lang.System.out.println(l2);
    return;

Выход компилятора Eclipse

public static void main(java.lang.String[]);
  Code:
   0:   ldc #16; //int 1073741823
   2:   istore_1
   3:   ldc #17; //int 2147483647
   5:   istore_2
   6:   lconst_0
   7:   lstore_3
   8:   ldc #16; //int 1073741823
   10:  istore  5
   12:  goto    22
   15:  lload_3
   16:  lconst_1
   17:  ladd
   18:  lstore_3
   19:  iinc    5, 1
   22:  iload   5
   24:  ldc #17; //int 2147483647
   26:  if_icmplt   15
   29:  getstatic   #18; //Field java/lang/System.out:Ljava/io/PrintStream;
   32:  lload_3
   33:  invokevirtual   #24; //Method java/io/PrintStream.println:(J)V
   36:  lconst_0
   37:  lstore_3
   38:  ldc #16; //int 1073741823
   40:  istore  5
   42:  goto    52
   45:  lload_3
   46:  lconst_1
   47:  ladd
   48:  lstore_3
   49:  iinc    5, 1
   52:  iload   5
   54:  ldc #17; //int 2147483647
   56:  if_icmplt   45
   59:  getstatic   #18; //Field java/lang/System.out:Ljava/io/PrintStream;
   62:  lload_3
   63:  invokevirtual   #24; //Method java/io/PrintStream.println:(J)V
   66:  return

Выходной сигнал:

    java.lang.String[] r0;
    int i0, i1, i3, i5;
    long l2, l4;

    r0 := @parameter0;
    i0 = 1073741823;
    i1 = 2147483647;
    l2 = 0L;
    i3 = 1073741823;
    goto label1;

 label0:
    l2 = l2 + 1L;
    i3 = i3 + 1;

 label1:
    if i3 < 2147483647 goto label0;

    java.lang.System.out.println(l2);
    l4 = 0L;
    i5 = 1073741823;
    goto label3;

 label2:
    l4 = l4 + 1L;
    i5 = i5 + 1;

 label3:
    if i5 < 2147483647 goto label2;

    java.lang.System.out.println(l4);
    return;

Интересно, что версия javac -produced использует if_icmpge в качестве условия выхода ( >= 2147483647) на int, что не должно иметь смысла (равное значение, но не больше). Оба выглядят корректно, поэтому я подозреваю, что JVM-ошибка.

Ответ 2

Есть ошибки, которые влияют на циклы, когда верхняя граница приближается к Integer.MAX_VALUE.

См. этот вопрос.

Ответ 3

В соответствии с Java-гуру это ошибка 5091921, исправлена ​​в JDK7, но не запланирована для исправления в JDK6.

Ответ 4

Возможно, это ошибочный цикл, разворачивающийся в HotSpot в 64-разрядной VM. Попробуйте запустить код с помощью -client или +XX:-AggressiveOpts.