2016-02-24 9 views
19

Я уже работал с -XX:+PrintCompilation, и я знаю основные методы JIT-компилятора и почему используется JIT-компиляция.Как JVM решил JIT-скомпилировать метод (классифицировать метод как «горячий»)?

Но я до сих пор не понял, как JVM решает JIT-скомпилировать метод, то есть «когда пришло время JIT-компиляции метода».

Действительно ли я в предположении, что каждый метод начинает интерпретироваться, и до тех пор, пока он не классифицируется как «горячий метод», он не будет скомпилирован? У меня что-то в затылке, что я прочитал, что метод считается «горячим», когда он был выполнен не менее 10 000 раз (после интерпретации метода 10 000 раз он будет скомпилирован), но я должен признать, что я не уверен в этом или где я это читал.

Так подытожить мой вопрос:

(1) Является ли каждый метод интерпретированы, пока не были классифицированы как «горячим» методом (и, следовательно, был составлен) или есть причины для методов скомпилировать, даже если они не «горячие»?

(2) Как JVM классифицирует методы в «не горячие» и «горячие» методы? Номер исполнения? Что-нибудь еще?

(3) Если существуют определенные пороговые значения (например, количество исполнений) для «горячих» методов, существуют ли флаги Java (-XX:...) для установки этих пороговых значений?

+0

Посмотрите на выходе '-XX: + PrintFlagsFinal', есть много флагов, относящихся к составителям JIT и их уровни, встраивание, методы размеров, компилятор нить и т.д. – the8472

ответ

36

Политика компиляции HotSpot довольно сложна, особенно для многоуровневой компиляции, которая по умолчанию включена в Java 8. Это не число исполнений, а вопрос CompileThreshold.

Лучшее объяснение (по-видимому, только разумное объяснение) можно найти в источниках HotSpot, см. advancedThresholdPolicy.hpp.

Я суммировать основные моменты этой передовой политики компиляции:

  • Выполнение начинается с уровня 0 (переводчика).
  • Основные триггеры для компиляции являются
    1. вызов метода счетчик i;
    2. запасной счетчик b. Обратные ветви обычно обозначают цикл в коде.
  • Каждый раз, когда счетчики достигают определенное значение частоты (TierXInvokeNotifyFreqLog, TierXBackedgeNotifyFreqLog), политика сборника призвана решить, что делать дальше с запущенным методом. В зависимости от значений i, b и тока нагрузки C1 и C2 потоков компилятора может быть принято решением

    • продолжить выполнение в переводчике;
    • начало профилирования в интерпретаторе;
    • метод компиляции с C1 на уровне 3 с полными данными профиля, необходимыми для последующей перекомпиляции;
    • метод компиляции с C1 на уровне 2 без профиля, но с возможностью перекомпиляции (маловероятно);
    • окончательно скомпилировать метод с C1 на уровне 1 без профиля или счетчиков (также маловероятно).

    Ключевыми параметрами являются TierXInvocationThreshold и TierXBackEdgeThreshold. Пороги могут быть динамически настроены для данного метода в зависимости от длины очереди компиляции.

  • Очередь компиляции не является FIFO, а скорее приоритетной.

  • C1-скомпилированный код с данными профиля (уровень 3) ведет себя аналогичным образом, за исключением того, что пороговые значения для перехода на следующий уровень (C2, уровень 4) намного больше. Например. интерпретируемый метод может быть скомпилирован на уровне 3 после примерно 200 вызовов, тогда как С1-скомпилированный метод подлежит повторной компиляции на уровне 4 после 5000+ вызовов.

  • Специальная политика используется для inline метода. Крошечные методы могут быть включены в вызывающий, даже если они не «горячие». Несколько более крупные методы могут быть встроены только в том случае, если они вызываются часто (InlineFrequencyRatio, InlineFrequencyCount).
+0

Эта ссылка действительно полезна и содержит все, что я хотел знать. Вы правы, трудно найти _раздельную информацию там, еще не прочитали ничего подробного о многоуровневой компиляции, скорее всего, никогда этого не сделают. Спасибо! –

+2

Ключевым понятием для меня является то, что нормальный путь равен 0 (интерпретируется) -> 3 (C1, полное профилирование) -> 4 (C2). На этом пути C1 действительно существует только для сбора данных профиля для C2 для работы. –

+3

Есть три дополнительных альтернативных пути. (1) Если сборник C1 обнаруживает, что метод тривиален, он скомпилирован в 1 (C1, без профилирования), потому что 4 (C2) не будет быстрее. (2) Если компилятор C2 занят, метод скомпилируется в 2 (C1, профилирование света) до тех пор, пока C2 не будет менее занят, после чего он будет перекомпилирован с 3 C1, полным профилированием), поэтому он может продолжить до 4 (С2). (3) Если C1 занят, но C2 нет, профилирование выполняется в интерпретаторе, поэтому метод может перейти прямо в C2, не пройдя через C1. –

6

Основной параметр для управления это -XX:CompileThreshold=10000

Hotspot для Java-теперь использует многоуровневые компиляции по умолчанию, используя ряд этапов компиляции от уровня 1 до 4. Я считаю, что 1 не оптимизации. Уровень 3 - C1 (на основе клиентского клиента), а уровень 4 - C2 (на основе компилятора сервера)

Это означает, что небольшая оптимизация может произойти раньше, чем вы могли ожидать, и она может продолжать оптимизацию уже после ее достижения порог 10K. Самое высокое, что я видел, - это анализ эвакуации, исключающий StringBuilder после миллиона звонков.

Примечание: цикл, повторяющийся много раз, может вызвать компилятор. например достаточно петли в 10K раз.

1) До тех пор, пока метод считается достаточно горячим, он интерпретируется. Однако некоторые JVM (например, Azul Zing) могут компилировать методы при запуске, и вы можете заставить JVM Hotspot скомпилировать метод через внутренний API. Java 9 также может иметь компилятор AOT (Ahead Of Time), но он все еще изучается. AFAIK

2) Количество вызовов или количество итераций.

3) Да -XX:CompileThreshold= является основным.

+0

У вас есть дополнительные материалы где Я мог бы прочитать об этом? Я знаю о C1 и C2, но я не слышал о уровнях компиляции 1-4 (Interpeter, C1, C2 было бы 3 уровня). И вы в основном говорите, что метод может считаться горячим ниже 'CompilerThreshold'. Что это за порог? Могу ли я предположить, что метод считается горячим _ последним, когда он назывался 'CompilerThreshold' раз? –

+0

Извините за последующий вопрос, но только для правильной терминологии: могу ли я назвать метод «горячим», если он был оптимизирован хотя бы один раз, или это точно определение «горячего метода»? –

+1

@MarkusWeninger Это то, что меняется от обновления к обновлению. Если вы вызываете один и тот же набор кода много раз (но каждый раз), вы можете видеть, что они не все скомпилируются сразу. Фактическое альго намного сложнее.Лучшее место для большей информации, я подозреваю, является источником. Все написанное может быть устаревшим для текущей JVM. –