0

Java Reflection: Почему это так медленно?

10

Вопрос о производительности рефлексии в Java

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

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

class B {

}

public class Test {

    public static long timeDiff(long old) {
        return System.currentTimeMillis() - old;
    }

    public static void main(String args[]) throws Exception {

        long numTrials = (long) Math.pow(10, 7);

        long millis;

        millis = System.currentTimeMillis();

        for (int i=0; i<numTrials; i++) {
            new B();
        }
        System.out.println("Обычная инициализация заняла: "
                 + timeDiff(millis) + "ms");

        millis = System.currentTimeMillis();

        Class<B> c = B.class;

        for (int i=0; i<numTrials; i++) {
            c.newInstance();
        }

        System.out.println("Инициализация с помощью рефлексии заняла:" 
              + timeDiff(millis) + "ms");

    }
}

Таким образом, у меня есть несколько вопросов:

  1. Почему рефлексия так медлительна? Делал ли я что-то неправильно? (даже приведённый пример демонстрирует значительную разницу). Мне трудно поверить, что это может быть в 100 раз медленнее, чем обычная инициализация.

  2. Есть ли другие подходы для работы с кодом как с данными (учитывая, что я по-прежнему ограничен в использовании Java)?

2 ответ(ов)

0

При первом введении рефлексии её производительность была довольно низкой, но в более современных версиях JRE она значительно улучшилась. Тем не менее, использование рефлексии в внутреннем цикле может не быть хорошей идеей. Код, основанный на рефлексии, обладает низким потенциалом для оптимизаций с помощью JIT-компиляции.

Рефлексия чаще всего используется для соединения слабо связанных компонентов, то есть для поиска конкретных классов и методов, когда известны только интерфейсы. Примеры использования включают фреймворки внедрения зависимостей, создание экземпляров классов JDBC или парсеры XML. Эти операции часто могут выполняться один раз при старте системы, так что небольшая неэффективность в таких случаях не имеет значения.

0

Ответ на ваш вопрос:

Код @Tim Bender выдает следующие результаты на моей машине (jdk_1.8_45, os_x 10.10, i7, 16 ГБ):

Время инициализации через рефлексию: 1139 мс
Обычная инициализация: 4969 мс

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь