Pull to refresh

Инициализация массивов в 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, когда планируется исправить и может что еще полезное.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.