Для написания высокоэффективного и производительного Java-кода, оптимизации кода под определенные требования, всегда полезно подключить к JVM определенные утилиты, чтобы собрать метрики производительности, заглянуть внутрь и оценить поведение системы под разными нагрузками и в различных ситуациях. Ниже я привожу список утилит, которые я часто использую для этой цели.
Программы
VisualVM
раньше в составе JDK были две утилиты: jconsole и visualvm, теперь jconsole удалена, а с Java 9 visualvm поставляется отдельно. Незаменимый помощник для профилирования кода. Бесплатен. Куча плагинов для профилирования кода и сбора статистики.
Java Mission Control
Раньше эта утилита шла в составе JDK. Теперь она выделена в отдельный проект. Старая jmc не понимает дампов новых JVM. Поэтому, если перешли на java12+ надо выкачивать JMC 7 (или уже JMC 8). Алексей Шипилёв на своем сайте в тёмной каморке выкладывает свежие билды JMC под MacOS X, Windows и Linux. Спасибо! Про JMC есть подробная презентация от Алексея Рагозина.
Update 2021.04.16: JMС ver.8 вышел. Правда с какими-то совершенно нелепыми багами.
Update 2022.01.17: JMC ver.8.1.0 вышел с исправлениями, улучшениями и дополнениями.
jmh
микробенчмаркинг от Алексея Шипилёва (см. презентацию). Была раньше отдельная библиотека, теперь идет в составе JDK.
jmx
Java-интерфейс, через который можно собирать статистику с работающего приложения и управлять его свойствами.
[ См. также: Полезные Linux-команды — несколько утилит OS Lnux для оценки производительности системы ]
Утилиты JDK
javap декомпилятор в байткод. Все знают javac — компилятор, превращающий ваш исходник в байт-код. javap проделывает обратную операцию. Он декомпилирует байт-код в мнемо-код, который можно прочитать и понять, в какие именно байт-инструкции транслируются те или иные порции вашего исходного кода.
Для мониторинга приложения и сбора статистики можно использовать утилиты jps, jinfo, jstack и jmap.
Например, утилита jps:
# jps -mlv
выведет список только Java-процессов на данной машине (в отличие от стандартного Unix/Linux ps). Выведет id процесса, его Main-class и параметры, с которыми процесс был запущен. Main-class и параметры полезны, чтобы отличить один процесс от другого, если у вас запущено несколько вариантов одной и той же программы с разными параметрами.
Утилита jmap:
# jmap -heap <pid>
выведет дамп памяти вашей Java-программы. Увы, работает только с Java 8, если утилита jmap из Java 8 JDK. Утилита считается экспериментальной и в новых JDK не поддерживается.
Утилита jinfo:
# jinfo <pid>
выведет много-много полезной информации о параметрах JVM, флагах, аргументах запуска программы.
Утилита jstack:
# jstack <pid>
выведет дамп всех потоков вашей Java-программы. В дампе можно разглядеть, какой поток чем занимался в момент дампа: какой работал (и в каком месте кода он находился), какой — заблокирован, какой находится в ожидании и так далее. Эта информация полезна, если надо определить, где именно находится deadlock, или в каком месте конкретный «жадный» поток отъедает массу ресурсов.
[ См. также: Утилиты pidstat и jstack — заглядываем за кулисы Java-приложения ]
Стоит помянуть ещё одну полезную утилиту: jcmd. В новейших релизах JDK она заменяет старые утилиты, которые считаются устаревшими (deprecated) и экспериментальными (experimental) и больше не поддерживаются. Предполагается, что вместо зоопарка утилит jps, jinfo, jstack и jmap, достаточно освоить jcmd, которая эффективно заменит их все.
[ См. также: Как jcmd помогает настроить JVM для low-latency ]
С помощью jcmd можно запускать и останавливать внутренний монитор сбора статистики Java Flight Recorder. Статистику можно записывать в файл, который можно просмотреть другой утилитой — Java Mission Control (о ней было уже сказано выше).
Обратите внимание, что в команде надо указывать pid процесса. Все дело в том, что у вас на машине может работать несколько Java-приложений под разными JVM. Например, у меня одно приложение до сих пор работает под Java 8, а другое — уже под Java 13. И для каждой JVM имеется свой набор команд, который поддерживает jcmd. Поэтому на некоторые команды Java8 может сказать «Not supported».
Сбор статистики как рутина
Важное замечание: При обращении данных утилит к JVM для сбора статистики, JVM должна на короткое время сбора данных остановиться сама и остановить все работающие потоки вашего приложения. Это значит не следует собирать статистику на PROD-е в критические для вашей системы моменты. Как правило я планирую сбор статистики с помощью утилиты cron на определенные часы, когда рынок закрыт, торги не ведутся и останов JVM на короткое время ничему не критическому не помешает.
Автоматизация сбора статистики позволяет собирать данные за несколько дней и даже месяцев и точно следить за поведением и состоянием системы изо дня в день. Еще позволяет вам заметить изменения на PROD или QA серверах, которые были сделаны без вашего ведома технической командой (такое тоже бывает): патчи операционной системы, апгрейд версии Java, новые параметры командной строки. Например, неожиданно большие размеры данных в heap позволяют предположить, что в данный день в поведении вашего приложения были какие-то не рядовые события: через систему прошло необычно много запросов, где-то в системе произошел затык и она не успевала обрабатывать все данные, словом, что-то не обычное.
Java Agents
JVM имеет Java Agents API, который позволяет подключать к JVM сторонние утилиты. Java agents — это «агенты», написанные на Java. Подключаются к приложению при старте с помощью параметра:
-javaagent:<path-to-agent-jar>=<options>
JVM TI-агенты — другой способ подключить стороннюю утилиту к JVM при старте. JVMTI-агенты пишутся на C или C++. Они позволяют глубже заглянуть во внутренности JVM, но при этом высок риск грохнуть ее. Подключаются к приложению при старте с помощью параметра:
-agentlib:<agent-lib-name>=<options>
или
-agentpath:<path-to-agent>=<options>
Сторонние утилиты
Профилировщики — специальные утилиты, нацеленные на исследование качества исполнения вашего кода в JVM. Самым популярным является пожалуй YourKit. Но большинство профилировщиков — платные и требуют лицензии для коммерческого использования.
JITWatch — отличная open-source утилита, показывающая стадии компиляции вашего кода JIT-компилятором во время исполнения.