Ответ 1
Да, существует оптимизация для снижения расходов на отражение, хотя она реализована в основном в библиотеке классов, а не в JVM.
До того, как Java 1.4 Method.invoke
работал через вызов JNI во время выполнения VM. Для каждого вызова требовалось как минимум два перехода с Java на Native и обратно на Java. Время выполнения VM проанализировало подпись метода, проверило, что типы переданных аргументов были правильными, выполнялся бокс/распаковка и построил новый Java-фрейм для вызываемого метода. Все это было довольно медленно.
Так как Java 1.4 Method.invoke
использует генерацию динамического байт-кода, если метод вызывается более 15 раз (настраивается через sun.reflect.inflationThreshold
системное свойство). Специальный класс Java, отвечающий за вызов данного конкретного метода, встроен во время выполнения. Этот класс реализует sun.reflect.MethodAccessor, который java.lang.reflect.Method
делегирует вызовы.
Подход с генерацией динамического байткода намного быстрее, поскольку он
- не страдает от накладных расходов JNI;
- не нужно каждый раз анализировать подпись метода, потому что каждый метод, вызванный через Reflection, имеет свой собственный уникальный MethodAccessor;
- может быть дополнительно оптимизирована, например. эти MethodAccessors могут извлечь выгоду из всех регулярных оптимизаций JIT, таких как inlining, постоянное распространение, устранение автобоксинга и т.д.
Обратите внимание, что эта оптимизация реализована главным образом в Java-коде без помощи JVM. Единственное, что делает HotSpot VM, чтобы сделать эту оптимизацию возможной - пропускает проверку байт-кода для таких генерируемых MethodAccessors. В противном случае верификатор не разрешил бы, например, вызвать частные методы.