Согласно JLS, int
массив должен быть заполнен нулями сразу после инициализации. Однако я столкнулся с ситуацией, когда это не так. Такое поведение происходит сначала в JDK 7u4, а также во всех последующих обновлениях (я использую 64-битную реализацию). Следующий код вызывает исключение:
public static void main(String[] args) {
int[] a;
int n = 0;
for (int i = 0; i < 100000000; ++i) {
a = new int[10];
for (int f : a)
if (f != 0)
throw new RuntimeException("Array just after allocation: "+ Arrays.toString(a));
Arrays.fill(a, 0);
for (int j = 0; j < a.length; ++j)
a[j] = (n - j)*i;
for (int f : a)
n += f;
}
System.out.println(n);
}
Исключение возникает после того, как JVM выполняет компиляцию блока кода, и не возникает с -Xint
флагом. Кроме того, этот Arrays.fill(...)
оператор (как и все другие операторы в этом коде) является необходимым, и исключение не возникает, если оно отсутствует. Понятно, что эта возможная ошибка ограничена некоторой оптимизацией JVM. Есть идеи по поводу такого поведения?
Обновление:
я вижу такое поведение на 64-битной серверной виртуальной машине HotSpot, версии Java с 1.7.0_04 до 1.7.0_10 в Gentoo Linux, Debian Linux (обе версии ядра 3.0) и MacOS Lion. Эту ошибку всегда можно воспроизвести с помощью приведенного выше кода. Я не тестировал эту проблему с 32-битным JDK или в Windows. Я уже отправил отчет об ошибке в Oracle (идентификатор ошибки 7196857), и через несколько дней он появится в общедоступной базе данных ошибок Oracle.
Обновление:
Oracle опубликовала эту ошибку в своей общедоступной базе данных ошибок: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196857
Ответы:
Здесь мы столкнулись с ошибкой в JIT-компиляторе. Компилятор определяет, что выделенный массив заполнен после выделения
Arrays.fill(...)
, но проверка использования между выделением и заполнением ошибочна. Итак, компилятор выполняет недопустимую оптимизацию - пропускает обнуление выделенного массива.Эта ошибка помещена в трекер ошибок Oracle ( идентификатор ошибки 7196857 ). К сожалению, я не дождался разъяснений от Oracle по следующим пунктам. Как я вижу, эта ошибка специфична для ОС: она абсолютно воспроизводима на 64-битных Linux и Mac, но, как я вижу из комментариев, воспроизводится не регулярно в Windows (для аналогичных версий JDK). Кроме того, было бы неплохо узнать, когда эта ошибка будет исправлена.
На данный момент есть только совет: не используйте JDK1.7.0_04 или более позднюю версию, если вы зависите от JLS для вновь объявленных массивов.
Обновление от 5 октября:
В новой сборке 10 JDK 7u10 (ранний доступ), выпущенной 4 октября 2012 г., эта ошибка была исправлена, по крайней мере, для ОС Linux (для других я не тестировал). Спасибо @Makoto, который обнаружил, что эта ошибка больше не доступна для публичного доступа в базе данных ошибок Oracle. К сожалению, я не знаю, по каким причинам Oracle удалила его из общего доступа, но он доступен в кеше Google . Кроме того, эта ошибка привлекла внимание Redhat: ей были присвоены идентификаторы CVE CVE-2012-4420 ( bugzilla ) и CVE-2012-4416 ( bugzilla ).
источник
Я внес некоторые изменения в ваш код. Это не проблема целочисленного переполнения. Посмотрите код, он выдает исключение во время выполнения
источник