Подтвердить что ты не робот

Как JVM решила JIT-компилировать метод (классифицировать метод как "горячий" )?

Я уже работал с -XX:+PrintCompilation, и я знаю основные методы JIT-компилятора и почему используется JIT-компиляция.

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

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

Итак, подведем итог моему вопросу:

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

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

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

4b9b3361

Ответ 1

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

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

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

  • Выполнение начинается с уровня 0 (интерпретатор).
  • Основные триггеры для компиляции:
    • счетчик вызовов i;
    • счетчик 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+ -оквотов.

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

Ответ 2

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

Hotspot для Java 8 теперь использует многоуровневую компиляцию по умолчанию, используя несколько этапов компиляции с уровня 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= является основным.