Добрый день!
Недавно я обнаружил следующий баг (Bug ID 7196857) в JVM начиная с версии 1.7.0_04 и выше. Согласно спецификации Java, массивы инициализируются заполненными default-значениями: в частности массив
Как видно из кода, исключение сработает только если массив изначально инициализирован с ненулевыми значениями. Сам же баг связан с оптимизацией при JIT-компиляциии и исключение выскочит только тогда, когда JVM скомпилирует соответствующий участок кода (соответственно ошибки не будет если запускать машину только в режиме интерпретатора — с флагом
Этот баг стабильно воспроизводится с 64- и 32-битными JDK начиная с версии 1.7.0_04 и включая последнюю сборку 1.7.0_10 (b06) на 64-битных системах Linux и Mac OS. Есть неопределенность с воспроизводимостью на 32-битных системах и Windows: у кого-то ошибка воспроизвидится, у кого-то нет (в часности у меня на Windiws 7 64 с JDK1.7.0_07 ошибки нет ).
Вывод: если вы полагаетесь на default-значения при инициализации массивов, то лучше не используйте JDK 1.7.0_04 и выше пока ошибка не будет исправлена.
Ссылки:
1. Java Language Specification 4.12.5.
2. Баг на сайте Oracle.
3. Обсуждение на Stackoverflow.
P.S. Зная, что ресурс посещают люди из Oracle, хотелось бы по возможности узнать дополнительную информацию — о специфичности бага для различных OS, когда планируется исправить и может что еще полезное.
Недавно я обнаружил следующий баг (Bug ID 7196857) в JVM начиная с версии 1.7.0_04 и выше. Согласно спецификации Java, массивы инициализируются заполненными default-значениями: в частности массив
int[]
должен быть заполнен нулями сразу после инициализации. Многие программисты (в том числе и ваш покорный слуга) частенько полагаются на это при написании кода. Не так давно я обнаружил, что начиная с JDK версии 1.7.0_04 при определенных условиях этого не происходит. Следующий код выбрасывает исключение: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);
}
Как видно из кода, исключение сработает только если массив изначально инициализирован с ненулевыми значениями. Сам же баг связан с оптимизацией при JIT-компиляциии и исключение выскочит только тогда, когда JVM скомпилирует соответствующий участок кода (соответственно ошибки не будет если запускать машину только в режиме интерпретатора — с флагом
-Xint
). Компилятор правильно распознает, что аллоцируемый массив вскоре заполняется в строке Arrays.fill(...)
, однако не определяет, что к массиву происходят обращения и до вызова этой комманды. Таким образом, компилятор применяет недопустимую в данной ситуации оптимизацию — опускает заполнение аллоцированного массива default-значениями. Этот баг стабильно воспроизводится с 64- и 32-битными JDK начиная с версии 1.7.0_04 и включая последнюю сборку 1.7.0_10 (b06) на 64-битных системах Linux и Mac OS. Есть неопределенность с воспроизводимостью на 32-битных системах и Windows: у кого-то ошибка воспроизвидится, у кого-то нет (в часности у меня на Windiws 7 64 с JDK1.7.0_07 ошибки нет ).
Вывод: если вы полагаетесь на default-значения при инициализации массивов, то лучше не используйте JDK 1.7.0_04 и выше пока ошибка не будет исправлена.
Ссылки:
1. Java Language Specification 4.12.5.
2. Баг на сайте Oracle.
3. Обсуждение на Stackoverflow.
P.S. Зная, что ресурс посещают люди из Oracle, хотелось бы по возможности узнать дополнительную информацию — о специфичности бага для различных OS, когда планируется исправить и может что еще полезное.