Какова Стоимость Вызова array.length

Вот официальная страница начинающего от Mozilla для записи Вашего первого расширения. http://developer.mozilla.org/en/Building_an_Extension

50
задан jjnguy 30 July 2009 в 07:45
поделиться

8 ответов

Нет, вызов array.length - это O (1) или операция с постоянным временем.

Поскольку .length является (действует как) public final членом массива , доступ к нему не медленнее, чем к локальной переменной. (Это сильно отличается от вызова такого метода, как size () )

Современный JIT-компилятор, вероятно, в любом случае сразу оптимизирует вызов .length .

Вы можете подтвердить это, просмотрев исходный код JIT-компилятора в OpenJDK или заставив JVM выгрузить собственный код, скомпилированный JIT, и изучив этот код.

Обратите внимание, что могут быть случаи, когда компилятор JIT не может этого сделать; например

  1. , если вы отлаживаете включающий метод, или
  2. , если тело цикла имеет достаточно локальных переменных для принудительного заполнения регистров.
69
ответ дан 7 November 2019 в 10:44
поделиться

У меня было немного времени за обедом:

public static void main(String[] args) {
    final int[] a = new int[250000000];
    long t;

    for (int j = 0; j < 10; j++) {
        t = System.currentTimeMillis();
        for (int i = 0, n = a.length; i < n; i++) { int x = a[i]; }
        System.out.println("n = a.length: " + (System.currentTimeMillis() - t));

        t = System.currentTimeMillis();
        for (int i = 0; i < a.length; i++) { int x = a[i]; }
        System.out.println("i < a.length: " + (System.currentTimeMillis() - t));
    }
}

Результаты:

n = a.length: 672
i < a.length: 516
n = a.length: 640
i < a.length: 516
n = a.length: 656
i < a.length: 516
n = a.length: 656
i < a.length: 516
n = a.length: 640
i < a.length: 532
n = a.length: 640
i < a.length: 531
n = a.length: 641
i < a.length: 516
n = a.length: 656
i < a.length: 531
n = a.length: 656
i < a.length: 516
n = a.length: 656
i < a.length: 516

Примечания:

  1. Если вы перевернете тесты, то n = a.length показывает, что он быстрее, чем i примерно наполовину, вероятно, из-за сборки мусора (?).
  2. Я не мог сделать 250000000 намного больше, потому что я OutOfMemoryError at 270000000 .

Дело в том, и это то, что делали все остальные, вам нужно запустить Java из памяти, а вы все еще не видите значительная разница в скорости между двумя альтернативами. Тратьте свое время на разработку на действительно важные вещи.

16
ответ дан 7 November 2019 в 10:44
поделиться

Я сомневаюсь, что есть какая-то существенная разница, и даже если бы она была, я готов поспорить, что она, вероятно, была оптимизирована во время компиляции. Вы зря теряете время, пытаясь микрооптимизировать подобные вещи. Сначала сделайте код читаемым и правильным, затем, если у вас возникнут проблемы с производительностью, используйте профилировщик , затем позаботьтесь о выборе более эффективных структур данных / алгоритмов, если это необходимо, , затем побеспокоитесь об оптимизации частей. ваш профайлер выделяет.

11
ответ дан 7 November 2019 в 10:44
поделиться

Длина массива хранится как переменная-член массива (не такая же, как элемент) в Java, поэтому выборка этой длины является операцией с постоянным временем, такой же, как чтение переменная-член из обычного класса. Многие старые языки, такие как C и C ++, не хранят длину как часть массива, поэтому вам нужно сохранить длину до начала цикла. В Java этого делать не обязательно.

7
ответ дан 7 November 2019 в 10:44
поделиться

В таком случае, почему бы вам не сделать обратный цикл:

for (int i = a.length - 1; i >= 0; --i) {
    ...
}

Здесь есть 2 микрооптимизации:

  • Поворот цикла
  • Постфиксный декремент
4
ответ дан 7 November 2019 в 10:44
поделиться

Этот ответ дан с точки зрения C #, но я думаю, что то же самое относится и к Java.

В C # идиома

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

распознается как повторение по массиву, поэтому проверка границ избегается при доступе к массиву в цикле, а не при каждом доступе к массиву.

Это может или не может быть распознано с помощью такого кода, как:

for (int i = 0, n = a.length; i < n; i++) {    ...}

или

n = a.length;

for (int i = 0; i < n; i++) {   ...}

Какая часть этой оптимизации выполняется компилятор против JITter, которого я не знаю, и, в частности, если он выполняется JITter, я бы ожидал, что все 3 будут генерировать один и тот же собственный код.

Однако первая форма также, возможно, более читабельна для людей, поэтому Я бы сказал, продолжай.

2
ответ дан 7 November 2019 в 10:44
поделиться

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

1
ответ дан 7 November 2019 в 10:44
поделиться

Может быть, было бы немного быстрее сохранить его в переменной. Но я был бы крайне удивлен, если бы профилировщик указал на это как на проблему.

На уровне байт-кода получение длины массива выполняется с помощью байт-кода arrayylength . Я не знаю, медленнее ли он, чем байт-код iload , но разницы не должно быть достаточно, чтобы заметить.

3
ответ дан 7 November 2019 в 10:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: