Производительность Java varargs - PullRequest
14 голосов
/ 11 марта 2010

Кодирование Я пришел проверить производительность Vararg в Java.

Я пишу следующий тестовый код:

public class T {

    public static void main(String[] args) {

        int n = 100000000;
        String s1 = new String("");
        String s2 = new String("");
        String s3 = new String("");
        String s4 = new String("");
        String s5 = new String("");

        long t = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            foo();
        }
        System.err.println(System.currentTimeMillis() - t);


        t = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            baz(s1, s2, s3, s4, s5);
        }
        System.err.println(System.currentTimeMillis() - t);

        t = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            bar(s1, s2, s3, s4, s5);
        }
        System.err.println(System.currentTimeMillis() - t);

    }

    static void foo() {
    }

    static void bar(String a1, String a2, String a3, String a4, String a5) {
    }

    static void baz(String... a) {
    }
}

На моей машине средняя производительность:

78
4696
78

Кажется, что передача переменных в методы бесплатна ?! Хорошо!

Но использование varags медленнее в 60 раз! Почему?

Объяснение может состоять в том, что программа должна создать массив в куче, а время тратит GC. Но для меньшего количества циклов я все еще получаю как вывод:

0
62
0

На что тратится это дополнительное время, и в любом случае у компилятора есть вся информация, чтобы разрешить это в вызове переменной fix ...

Это не мое намерение оптимизировать для этого, но я нашел это любопытным ...

Обновление

Я добавил новый тест

t = System.currentTimeMillis();
for (int i = 0; i < n; i++) {
    baz(s1);
}
System.err.println(System.currentTimeMillis() - t);

И эта версия с одним аргументом все еще в 30 раз медленнее. Может быть, за сценой стоит ArrayList.toArray ()?

Так что помните о ненужных методах varags в вашем коде и рефакторинге для фиксированной длины. Это может быть повышение производительности.

Ответы [ 4 ]

18 голосов
/ 11 марта 2010

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

Varargs является эквивалентом массива. Чтобы вызвать такой метод, необходимо создать и заполнить массив во время выполнения. Вот почему вы наблюдаете разницу.

String[] и String... являются синонимами. Если вы сравнили их, вы должны увидеть идентичную производительность.

8 голосов
/ 07 мая 2013

Используя как последнюю версию JRE6, так и JRE7, я получаю результаты, отличные от ваших, и они показывают, что varargs в 5 раз быстрее:

69
69
311

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

627
7470
7844

Вывод: не стесняйтесь использовать varargs .Если ваша функция тривиальна, то ее вызов будет встроен JIT, а если нет, то издержки на varargs, вероятно, будут незначительными.

1 голос
/ 11 марта 2010

Интересная проблема!

Это всего лишь предположение: за кулисами Var-args - это просто массивы. Создание этого неявного массива и заполнение его параметрами var-args может занять некоторое время; отсюда и производительность. Ну, я думаю.

0 голосов
/ 11 марта 2010

Как уже говорилось, массив поддерживается при использовании var-args ...,

, вам также следует попытаться увидеть влияние добавления "final" к параметрам каждого метода

лично я получаю улучшение с 2250 -> 2234 мс для массива.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...