Расчет длины массива кеша Java в циклах

Допустим, у меня есть массив, который я хотел бы перебрать:

int[] someArray = {1,2,3,4}

for (int i = 0; i < someArray.length; i++) {

    // do stuff
}

Будет ли эта длина массива вычисляться с каждой итерацией или будет оптимизирована для вычисления только один раз?

Должен ли я перебирать массивы, вычисляя длину заранее и передавать ее в цикл?

for (int i = 0, length = someArray.length; i < length ; i++) {

    // do stuff
}

person John    schedule 10.06.2015    source источник


Ответы (3)


Как всегда для производительности: напишите самый простой код, какой сможете, и протестируйте его, чтобы убедиться, что он работает достаточно хорошо.

Если вам нужен только элемент (а не индекс), я бы посоветовал вам использовать расширенный цикл for:

for (int value : array) {
    ...
}

Согласно JLS 14.14.2 это в основном эквивалентно вашему первому фрагменту кода, но код говорит только о том, что вас действительно интересует.

Но если вам действительно нужен индекс и предполагается, что вы нигде не изменяете array, я полагаю, что JIT-компилятор оптимизирует собственный код, чтобы получить длину только один раз. Получение длины — это операция O(1), поскольку в основном это просто поле в массиве, но, очевидно, это требует обращения к памяти, поэтому для событийного кода лучше сделать это только один раз. . но это не значит, что ваш код должен это делать. Обратите внимание, что я не ожидаю, что компилятор Java (javac) выполнит эту оптимизацию — я ожидаю, что это сделает JIT.

На самом деле, я считаю, что хороший JIT действительно увидит такой код:

for (int i = 0; i < array.length; i++) {
    int value = array[i];
    ...
}

и иметь возможность оптимизировать проверки границ массива - он может распознать, что если он все время обращается к одному и тому же объекту массива, это не может привести к ошибке с ошибкой границ массива, поэтому он может избежать проверки. Он может сделать то же самое для более "умного" кода, который заранее выбирает длину, но оптимизация JIT часто преднамеренно нацелена на очень распространенные шаблоны кода (чтобы получить наибольшую "отдачу от вложенных средств" ), а описанный выше способ перебора массива очень распространен.

person Jon Skeet    schedule 10.06.2015
comment
В case-1 для каждой итерации используется инструкция arraylength байтового кода. Во втором случае доступ к локальной переменной будет происходить для каждой итерации. Итак, глядя на байт-код, case-2, кажется, имеет преимущество. Но да, JIT, скорее всего, оптимизирует это - person TheLostMind; 10.06.2015
comment
@TheLostMind: Да, это моя точка зрения: доверьте JIT справиться с этим и напишите самый чистый код, какой только сможете. - person Jon Skeet; 10.06.2015

Начиная с JLS 7

10.7 Элементы массива

Членами типа массива являются все следующие элементы: • Поле public final length, которое содержит количество компонентов массива. длина может быть положительной или нулевой.

Возвращаясь к вашему вопросу, java не пересчитывает количество элементов в массиве на array.length. Он возвращает значение public final int length, вычисленное при создании массива.

person Sagar Gandhi    schedule 10.06.2015

Поскольку length является членом Array, он уже был установлен при создании массива. На каждой итерации вы получаете доступ только к этому свойству и ничего больше.

Так что либо вы получаете к нему доступ, как

    int myArrayLength=arr.length;
for(int i=0;i<myArrayLength;i++)

или как:

   for(int i=0;i<arr.length;i++)

Измеримого изменения производительности не будет.

person Neeraj Jain    schedule 10.06.2015
comment
Это не так просто .. jvm использует отдельную инструкцию байтового кода, называемую arrayLength, для определения длины массива - person TheLostMind; 10.06.2015