Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Есть ли способ дополнительно оптимизировать вызов рефлексивного метода Java?

Автор вопроса: NicholasОтветов: 5

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

Рассмотрим вспомогательный метод для рефлексивного вызова:

public static Object invoke(Object targetObject, String methodName, Object[] arguments, Class<?>[] signature)

Основная операция

return method.invoke(targetObject, arguments);

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

Ваше здоровье.

javaperformancereflection

Ответы

Ответ 1 · рейтинг 59 · Chris Jester-Young

Комментарии ниже относятся к реализации Sun, в частности OpenJDK 6. Ваш опыт может отличаться от других реализаций платформы Java.

java.lang.Class выполняет некоторое кэширование, поэтому реализация собственного кеша может не сильно улучшить ситуацию. Выполняйте временные тесты с ручным кэшированием и без него.

Фактический механизм вызова также оптимизирован. Первые 15 запусков (по умолчанию) вашего отраженного метода вызываются с использованием JNI; после этого создается байт-код, и вызов этого отраженного метода будет работать так же, как вызов этого метода непосредственно в коде Java.

Ответ 2 · рейтинг 8 · Nicholas

Я провел несколько тестов на основе ответа Криса Джестера-Янга и, используя параметры подробный, я определенно заметил, что компилятор предпринял некоторые действия вокруг 15-го вызова. Трудно сказать, есть ли большая разница в производительности без более сложного теста, но он убедителен. Вот результат:

Test# 0
Test# 1
Test# 2
Test# 3
Test# 4
Test# 5
Test# 6
Test# 7
Test# 8
Test# 9
Test# 10
Test# 11
Test# 12
Test# 13
Test# 14
[Loaded sun.reflect.ClassFileConstants from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.AccessorGenerator from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.MethodAccessorGenerator from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.ByteVectorFactory from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.ByteVector from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.ByteVectorImpl from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.ClassFileAssembler from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.UTF8 from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded java.lang.Void from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.Label from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.Label$PatchInfo from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded java.util.AbstractList$Itr from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.MethodAccessorGenerator$1 from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.ClassDefiner from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.ClassDefiner$1 from C:\jdk1.5.0_06\jre\lib\rt.jar]
[Loaded sun.reflect.GeneratedMethodAccessor1 from __JVM_DefineClass__]
Test# 15
Test# 16
Test# 17

Я полагаю, что бизнес InvokeDynamic не привлекает слишком много разработчиков из-за ускорения / устранения рефлексии.

Спасибо, Крис.

Ответ 3 · рейтинг 1 · Lawrence Dol

Вы определенно захотите отразить объект метода только один раз (вероятно, как частный статический) и использовать его для вызова, а не отражать его каждый раз. Не беспокойтесь о карте кеша, если вы не знаете имя во время компиляции.

Если это разумно в вашем контексте, вы можете захотеть закрепить и повторно использовать объект массива аргументов (не забудьте обнулить элементы массива при выходе из метода, чтобы предотвратить временное запрещение сборки мусора).

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

Я бы не стал делать ничего, кроме этого, по причинам, уже указанным в других ответах.

Ответ 4 · Bill K

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

Кроме того, есть большая вероятность, что сейчас или в будущем Java оптимизирует байт-код, так что вызов не будет стоить больше, чем вызов метода при использовании в цикле. Ваша "Оптимизация" может фактически помешать компиляторам делать что-то подобное. (Я знаю, что говорю нечетко, но это случилось - ОЧЕНЬ МНОГО).

Ответ 5 · Mike Dunlavey

Если стоимость вызова составляет менее 10% от стоимости того, что происходит в методе, вряд ли стоит беспокоиться.

Вы можете определить это, выполнив его 10 ^ 6 раз в цикле, с внутренним составом рутины и без него. Измерьте время с помощью секундомера, чтобы секунды переводились в микросекунды.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы