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

Почему JVM требует разминки?

Я понимаю, что в виртуальной машине Java (JVM) разминка потенциально необходима, поскольку Java загружает классы с использованием ленивого процесса загрузки, и поэтому вы хотите убедиться, что объекты инициализированы до начала основных транзакций. Я разработчик С++ и мне не приходилось сталкиваться с аналогичными требованиями.

Однако части, которые я не могу понять, следующие:

  • Какие части кода следует разогревать?
  • Даже если я разогреваю некоторые части кода, как долго он остается теплым (если этот термин означает только то, как долго ваши объекты класса остаются в памяти)?
  • Как это сделать, если у меня есть объекты, которые нужно создавать каждый раз, когда я получаю событие?

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

Обратите внимание, что приложение относится к высокочастотной торговле (HFT), поэтому производительность имеет чрезвычайно важное значение.

4b9b3361

Ответ 1

Какие части кода следует разогревать?

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

Даже после того, как ваш код разогревается, вы должны обеспечить, чтобы ваши кэши процессора также нагревались. Вы можете наблюдать значительное снижение производительности после операции блокировки, например. сеть IO, до 50 микросекунд. Обычно это не проблема, но если вы пытаетесь оставаться под 50 секунд в секунду, это будет проблемой большую часть времени.

Примечание. Warmup позволяет Escape Analysis ударить и поместить некоторые объекты в стек. Это означает, что такие объекты не нужно оптимизировать. Прежде чем оптимизировать код, лучше сохранить профиль своего приложения.

Даже если я разогреваю некоторые части кода, как долго он остается теплым (если этот термин означает только то, как долго ваши объекты класса остаются в памяти)?

Нет ограничений по времени. Это зависит от того, определяет ли JIt, было ли предположение, сделанное им при оптимизации кода, неверным.

Как это сделать, если у меня есть объекты, которые нужно создавать каждый раз, когда я получаю событие?

Если вам нужна низкая латентность или высокая производительность, вы должны создать как можно меньше объектов. Я собираюсь производить менее 300 КБ/сек. При такой скорости распределения вы можете иметь пространство Eden, достаточно большое, чтобы мелкий собирать один раз в день.

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

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

Обратите внимание, что приложение относится к высокочастотной торговле (HFT), поэтому производительность имеет чрезвычайно важное значение.

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

http://chronicle.software/

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

В частности, вас может заинтересовать https://github.com/OpenHFT/Java-Thread-Affinity, так как эта библиотека может помочь уменьшить дрожание планирования в ваших критических потоках.

И также сказано, что критические разделы кода, требующие разминки, должны выполняться (с поддельными сообщениями), по крайней мере, 12 тыс. раз, чтобы он работал оптимизированным образом. Почему и как это работает?

Код скомпилирован с использованием фоновых потоков. Это означает, что даже если метод может иметь право на компиляцию на собственный код, это не означает, что он сделал это esp при запуске, когда компилятор уже довольно занят. 12K не является необоснованным, но он может быть выше.

Ответ 2

Потепление относится к тому, что часть кода работает достаточно много раз, когда JVM перестает интерпретировать и компилировать на нативный (по крайней мере, в первый раз). Вообще то, что вы не хотите делать. Причина в том, что JVM собирает статистические данные о коде, о котором идет речь, что он использует при генерации кода (аналогично оптимизации, управляемой профилем). Поэтому, если рассматриваемый фрагмент кода "нагревается" поддельными данными, которые имеют разные свойства, чем реальные данные, вы могли бы повредить производительность.

EDIT: поскольку JVM не может выполнять статический анализ всей программы (он не может знать, какой код будет загружен приложением), он может вместо этого сделать некоторые догадки о типах из собранной статистики. В качестве примера, когда вы вызываете виртуальную функцию (на языке С++) в точном месте вызова, и она определяет, что все типы имеют одну и ту же реализацию, тогда вызов повышается до прямого вызова (или даже вложенного). Если позже это предположение, если оно окажется ошибочным, тогда старый код должен быть "нескомпилирован", чтобы вести себя правильно. AFAIK HotSpot классифицирует call-сайты как мономорфные (одиночные реализации), биморфные (в точности два.. преобразованные в if (imp1-type) {imp1} else {imp2}) и полную полиморфную... виртуальную отправку.

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

Ответ 3

Разогрев редко требуется. Это важно при выполнении, например, тестов производительности, чтобы убедиться, что время прогрева JIT не искажает результаты.

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

Если вы точно не знаете, что вам нужна какая-то разминка, не беспокойтесь об этом. Приведенное вами примерное приложение не нуждается в нем.

Ответ 4

Это все о компиляторе JIT, который используется в JVM для оптимизации байт-кода во время выполнения (поскольку javac не может использовать усовершенствованную или агрессивную технику оптимизации из-за не зависящей от платформы характера байт-кода)

  • вы можете разморозить код, который будет обрабатывать ваши сообщения. Фактически, в большинстве случаев вам не нужно делать это с помощью специальных циклов разминки: просто дайте приложению запустить и обработать некоторые из первых сообщений - JVM постарается сделать все возможное, чтобы проанализировать выполнение кода и сделать оптимизацию:) Ручная разминка с поддельными образцами может дать еще худшие результаты

  • код будет оптимизирован через некоторое время и будет оптимизирован до тех пор, пока какое-то событие в потоке программы не ухудшит состояние кода (после этого JIT компилятор попытается оптимизировать код еще раз - этот процесс никогда не заканчивается )

  • Объекты с короткими живыми объектами тоже могут быть оптимизированы, но в целом это должно помочь повысить эффективность кода обработки сообщений.

Ответ 5

Какие части кода следует разогревать?

В этом вопросе нет ответа. Это полностью зависит от вашего приложения.

Даже если я разогреваю некоторые части кода, как долго он остается теплым (предполагая, что этот термин означает только то, как долго остаются ваши объекты класса в памяти)?

Объекты остаются в памяти до тех пор, пока у вашей программы есть ссылка на них, отсутствует какое-либо специальное использование слабых ссылок или что-то подобное. Узнав о том, когда ваша программа "имеет ссылку" на что-то, может быть немного более неясной, чем вы могли бы подумать на первый взгляд, но она является основой для управления памятью на Java и стоит усилий.

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

Это полностью зависит от приложения. Ответ вообще отсутствует.

Я рекомендую вам учиться и работать с Java, чтобы понимать такие вещи, как загрузка классов, управление памятью и мониторинг производительности. Требуется некоторое количество времени для создания объекта, в общем, требуется больше времени для загрузки класса (что, конечно, обычно выполняется гораздо реже). Обычно, как только класс загружается, он остается в памяти для жизни программы - это то, что вы должны понимать, а не просто получить ответ.

Есть также методы, чтобы узнать, не знаете ли вы их уже. Некоторые программы используют "пулы" объектов, созданных до того, как они действительно нужны, а затем передаются для обработки после возникновения необходимости. Это позволяет критически важной для времени части программы избегать времени, затрачиваемого на создание экземпляра в критический период времени. Пулы сохраняют коллекцию объектов (10? 100? 1000? 10000?) И при необходимости создают дополнительные экземпляры, но управление пулами - это значительное программирование, и, конечно же, вы занимаете память с объектами в пулах,

Было бы вполне возможно использовать достаточное количество памяти, чтобы чаще запускать сборку мусора, и МЕДЛЕННУЮ СИСТЕМУ, КОТОРУЮ ВЫ НАХОДЯТСЯ С СКОРОСТЬЮ. Вот почему вам нужно понять, как это работает, а не просто "получить ответ".

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

- edit - добавить компиляцию "точно в срок" в список вещей для изучения и понимания.

Ответ 6

Почему JVM требует разминки?

Современные (J) виртуальные машины собирают статистику во время выполнения, какой код используется чаще всего и как он используется. Один (из сотен, если не тысяч) пример - это оптимизация вызовов виртуальных функций (в С++ lingo), которые имеют только реализацию. Эти статистические данные могут по их определению собираться только во время выполнения.

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

Какие части кода следует разогревать?

Часть, которая имеет решающее значение для производительности вашего приложения. Важная часть состоит в том, чтобы "разогреть его" так же, как и во время обычного использования, иначе будут сделаны неправильные оптимизации (и отменит их позже).

Даже если я разогреваю некоторые части кода, как долго он остается теплым (если этот термин означает только то, как долго ваши объекты класса остаются в памяти)?

Это действительно сложно сказать, что JIT-компилятор постоянно контролирует исполнение и производительность. Если будет достигнуто какое-то пороговое значение, он попытается оптимизировать ситуацию. Затем он продолжит мониторинг производительности, чтобы убедиться, что оптимизация действительно помогает. Если нет, это может привести к неоптимизации кода. Также может случиться, что недействительные оптимизации, такие как загрузка новых классов. Я бы подумал, что эти вещи не предсказуемы, по крайней мере, не на основе ответа stackoverflow, но есть инструменты, которые говорят вам, что делает JIT: https://github.com/AdoptOpenJDK/jitwatch

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

Одним простым примером может быть: вы создаете объекты внутри метода, так как ссылка выходит из области действия метода, эти объекты будут храниться в куче и в конечном итоге собираться сборщиком мусора. Если код, использующий эти объекты, сильно используется, он может оказаться вложенным в один большой метод, возможно, переупорядоченный до неузнаваемости, пока эти объекты не будут жить внутри этого метода. В этот момент их можно класть в стек и удалять, когда метод выходит. Это может сэкономить огромное количество мусора и будет происходить только после некоторого разминки.

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

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

Ответ 7

Я всегда представлял себе следующее:

Вы, как разработчик С++, могли представить автоматизированный итеративный подход jvm компиляции/горячей загрузки/замены различных бит фрагментами (мнимым аналогом) gcc -O0, -O1, -O2, -O3 варианты (и иногда возвращая их, если он сочтет это необходимым)

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

В стандартном jvm время, которое требуется для описания фрагмента для jit, устанавливается -XX:CompileThreshold, которое по умолчанию равно 1500. (Источники и версии jvm меняются - но я думаю, что для jvm8)

Далее книга, которую у меня есть под рукой в ​​разделе Host Performace JIT (p59), что во время JIT выполняются следующие оптимизации:

  • Встраивание
  • Блокировка устранения
  • Ликвидация виртуальных вызовов
  • Устранение записи в энергонезависимой памяти
  • Генерация собственного кода

EDIT:

относительно комментариев

Я думаю, что 1500 может быть достаточно, чтобы намекнуть JIT, что он должен скомпилировать код в нативный и стоп-интерпретацию. Вы согласны?

Я не знаю, является ли его просто подсказкой, но поскольку openjdk является открытым исходным кодом, вы можете просмотреть различные ограничения и числа в globals.hpp # l3559 @ver-a801bc33b08c (для jdk8u)

(Я не jvm dev, это может быть совершенно неправильное место для просмотра)

Компиляция кода в native не обязательно означает, что он также оптимизировано.

К моему пониманию - истина; особенно если вы имеете в виду -Xcomp (force compile) - этот blog даже утверждает, что он предотвращает выполнение jvm профилирования - следовательно, если вы не запустили -Xmixed (по умолчанию).

Таким образом, таймер запускается для выборочного частого доступа к собственному коду и оптимизируйте то же самое. Вы знаете, как мы можем контролировать этот интервал таймера?

Я действительно не знаю подробностей, но gobals.hpp я действительно определил некоторые частотные интервалы.