Как стать автором
Обновить

Инициализация массивов в Java: баг JVM версии 1.7.0_04 и выше

Добрый день!

Недавно я обнаружил следующий баг (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, когда планируется исправить и может что еще полезное.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.