Почему код Java, сгенерированный для выполнения операции, выполняется медленнее, чем «цикл интерпретатора»?

StackOverflow https://stackoverflow.com/questions/875695

Вопрос

У меня есть код Java, который выполняет побитовые операции с BitSet.У меня есть список операций, и я могу «интерпретировать» их, проходя по ним, но для меня важно, чтобы я мог выполнять эти операции как можно быстрее, поэтому я пытался динамически генерировать код для их применения.Я генерирую исходный код Java для выполнения операций и компилирую класс, реализующий эти операции, с помощью Javassist.

К сожалению, мой динамически сгенерированный код работает медленнее, чем интерпретируемый.Похоже, это связано с тем, что HotSpot оптимизирует интерпретируемый код, но не оптимизирует скомпилированный код:После того, как я запустил его несколько тысяч раз, мой интерпретируемый код работает в два раза быстрее, чем изначально, но мой скомпилированный код не показывает никакого ускорения.В соответствии с этой гипотезой мой интерпретируемый код изначально медленнее, чем скомпилированный, но в конечном итоге становится быстрее.

Я не уверен, почему это происходит.Я предполагаю, что, возможно, Javassist использует загрузчик классов, классы которого HotSpot не касается.Но я не являюсь экспертом в загрузке классов в Java, поэтому не уверен, является ли это разумным предположением или как его протестировать.Вот как я создаю и загружаю класс с помощью Javassist:

ClassPool pool = ClassPool.getDefault();
CtClass tClass = pool.makeClass("foo");

// foo implements MyInterface, with one method
tClass.addInterface(pool.get(MyInterface.class.getName()));

// Get the source for the method and add it
CtMethod tMethod = CtNewMethod.make(getSource(), tClass);
tClass.addMethod(tMethod);

// finally, compile and load the class
return (MyInterface)tClass.toClass().newInstance();

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

Я использую серверную JVM Sun 1.6 в 32-разрядной версии Windows XP.

Это было полезно?

Решение

HotSpot не важно, откуда взялся код.Например, он с радостью встроит код, вызываемый через вызов виртуального метода, с реализацией, загруженной другим загрузчиком классов.

Я предлагаю вам записать в исходном коде операции, которые вы пытаетесь выполнить для этого теста, а затем протестировать их.Обычно проще написать пример сгенерированного кода, чем писать генератор.

Существует ряд причин, по которым HotSpot может не оптимизировать код так сильно, как мог бы.Например, очень длинные методы, как правило, не встраиваются или в них встроен метод.

Другие советы

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

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

Если я запускаю тесты достаточно долго, я вижу, что мой сгенерированный код работает немного лучше, чем интерпретированный код.

Существуют настройки JVM, которые контролируют скорость компиляции кода -XX:CompileThreshold=10000.

Количество вызовов/ветвей метода перед компиляцией [-client:1500]

Не знаю, поможет ли это, потому что в вашем примере размер, похоже, играет жизненно важную роль.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top