Автор оригинала: Andrew Shcherbakov.
1. Обзор
В этом уроке мы рассмотрим Java Flight Recorder, его концепции, основные команды и способы его использования.
2. Утилиты мониторинга Java
Java – это не просто язык программирования, а очень богатая экосистема с множеством инструментов. JDK содержит программы, которые позволяют нам компилировать наши собственные программы, а также отслеживать их состояние и состояние виртуальной машины Java в течение всего жизненного цикла выполнения программы.
Папка bin дистрибутива JDK содержит, среди прочего, следующие программы, которые можно использовать для профилирования и мониторинга:
- Java VisualVM (jvisualvm.exe)
- JConsole (jconsole.exe)
- Java Mission Control (jmc.exe)
- Инструмент диагностических команд (jcmd.exe)
Мы предлагаем изучить содержимое этой папки, чтобы узнать, какие инструменты имеются в нашем распоряжении. Обратите внимание, что Java VisualVM в прошлом была частью дистрибутивов Oracle и OpenJDK. Однако, начиная с Java 9, дистрибутивы JDK больше не поставляются с Java VisualVM . Поэтому мы должны загрузить его отдельно с веб-сайта проекта с открытым исходным кодом VisualVM .
В этом уроке мы сосредоточимся на бортовом самописце Java. Этого нет среди инструментов, упомянутых выше, потому что это не автономная программа. Его использование тесно связано с двумя вышеперечисленными инструментами — средствами управления полетами Java и средствами диагностических команд.
3. Бортовой самописец Java и его основные концепции
Java Flight Recorder (JFR) – это инструмент мониторинга, который собирает информацию о событиях в виртуальной машине Java (JVM) во время выполнения приложения Java . JFR является частью дистрибутива JDK и интегрирован в JVM.
JFR предназначен для того, чтобы как можно меньше влиять на производительность запущенного приложения .
Чтобы использовать JFR, мы должны активировать его. Мы можем достичь этого двумя способами:
- при запуске приложения Java
- передача диагностических команд инструмента jcmd , когда приложение Java уже запущено
У JFR нет автономного инструмента. Мы используем Java Mission Control (JMC), который содержит плагин, позволяющий визуализировать данные, собранные JFR.
Эти три компонента — JFR , jcmd и JMC — образуют полный набор для сбора низкоуровневой информации о времени выполнения запущенной программы Java. Мы можем найти эту информацию очень полезной при оптимизации нашей программы или при ее диагностике, когда что-то идет не так.
Если на нашем компьютере установлены различные версии Java, важно убедиться, что компилятор Java ( javac ), средство запуска Java ( java ) и вышеупомянутые инструменты (JFR, jcmd и JMC) принадлежат одному и тому же дистрибутиву Java . В противном случае существует риск того, что вы не сможете увидеть какие-либо полезные данные, поскольку форматы данных JFR разных версий могут быть несовместимы.
JFR имеет две основные концепции: события и поток данных. Давайте кратко обсудим их.
3.1. События
JFR собирает события, которые происходят в JVM при запуске приложения Java. Эти события связаны с состоянием самой JVM или состоянием программы. Событие имеет имя, метку времени и дополнительную информацию (например, информацию о потоке, стеке выполнения и состоянии кучи).
Существует три типа событий , которые собирает JFR:
- мгновенное событие регистрируется сразу же, как только оно происходит
- событие длительности регистрируется, если его длительность превышает заданный порог
- пример события используется для выборки активности системы
3.2. Поток данных
События, которые собирает JFR, содержат огромное количество данных. По этой причине, по замыслу, JFR достаточно быстр, чтобы не мешать программе.
JFR сохраняет данные о событиях в одном выходном файле, flight.of.
Как мы знаем, операции дискового ввода-вывода довольно дороги. Поэтому JFR использует различные буферы для хранения собранных данных перед сбросом блоков данных на диск. Все может стать немного сложнее, потому что в один и тот же момент программа может иметь несколько процессов регистрации с различными параметрами.
Из-за этого мы можем найти в выходном файле больше данных, чем требуется, или они могут быть расположены не в хронологическом порядке . Мы можем даже не заметить этого факта, если используем JMC, потому что он визуализирует события в хронологическом порядке.
В некоторых редких случаях JFR может не очистить данные (например, при слишком большом количестве событий или в случае отключения электроэнергии). Если это произойдет, JFR попытается сообщить нам, что в выходном файле может отсутствовать часть данных.
4. Как использовать бортовой самописец Java
JFR является экспериментальной функцией, поэтому ее использование может быть изменено. На самом деле, в более ранних дистрибутивах мы должны активировать коммерческие функции, чтобы использовать их в производстве. Однако, начиная с JDK 11, мы можем использовать его, ничего не активируя. Мы всегда можем ознакомиться с официальными примечаниями к выпуску Java, чтобы узнать, как использовать этот инструмент.
Для JDK 8, чтобы иметь возможность активировать JFR, мы должны запустить JVM с опциями +UnlockCommercialFeatures и +FlightRecorder .
Как мы уже упоминали выше, существует два способа активации JFR. Когда мы активируем его одновременно с запуском приложения, мы делаем это из командной строки. Когда приложение уже запущено, мы используем инструмент диагностических команд.
4.1. Командная строка
Сначала мы компилируем файл *.java программы в *.class , используя стандартный компилятор java javac .
После успешной компиляции мы можем запустить программу со следующими опциями:
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=duration=200s,filename=flight.jfr path-to-class-file
где путь к файлу класса – это точка входа приложения *.class файл.
Эта команда запускает приложение и активирует запись, которая начинается немедленно и длится не более 200 секунд. Собранные данные сохраняются в выходном файле flight.jfr . Мы опишем другие варианты более подробно в следующем разделе.
4.2. Инструмент диагностических Команд
Мы также можем начать регистрацию событий с помощью инструмента cmd . Например:
jcmd 1234 JFR.start duration=100s filename=flight.jfr
До JDK 11, чтобы иметь возможность активировать JFR таким образом, мы должны запустить приложение с разблокированными коммерческими функциями:
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -cp ./out/ com.baeldung.Main
После запуска приложения мы используем его идентификатор процесса для выполнения различных команд, которые имеют следующий формат:
jcmd[parameters]
Вот полный список диагностических команд:
- JFR.start – запускает новую запись JFR
- JFR.check – проверяет выполнение записи JFR(ов)
- JFR.stop – останавливает конкретную запись JFR
- JFR.dump – копирует содержимое записи JFR в файл
Каждая команда имеет ряд параметров. Например, команда JFR.start имеет следующие параметры:
- имя – имя записи; оно служит для того, чтобы впоследствии ссылаться на эту запись с помощью других команд
- delay – параметр измерения для временной задержки начала записи, значение по умолчанию равно 0s
- duration – параметр измерения для временного интервала продолжительности записи; значение по умолчанию равно 0s, что означает неограниченное
- filename – имя файла, содержащего собранные данные
- maxage – размерный параметр для максимального возраста собранных данных; значение по умолчанию равно 0s, что означает неограниченный
- maxsize – максимальный размер буферов для собранных данных в байтах; значение по умолчанию равно 0, что означает отсутствие максимального размера
Мы уже видели пример использования этих параметров в начале этого раздела. Для получения полного списка параметров мы всегда можем обратиться к официальной документации Java Flight Recorded .
Хотя JFR предназначен для того, чтобы как можно меньше влиять на производительность JVM и приложения, лучше ограничить максимальный объем собранных данных , установив по крайней мере один из параметров: длительность , maxage или maxsize .
5. Бортовой самописец Java в действии
Давайте теперь продемонстрируем JFR в действии, используя пример программы.
5.1. Пример программы
Наша программа вставляет объекты в список до тех пор, пока не произойдет OutOfMemoryError . Затем программа спит в течение одной секунды:
public static void main(String[] args) { List
Без выполнения этого кода мы можем обнаружить потенциальный недостаток: цикл while приведет к высокой загрузке процессора и памяти. Давайте используем JFR, чтобы увидеть эти недостатки и, возможно, найти другие.
5.2. Начать Регистрацию
Сначала мы компилируем нашу программу, выполнив следующую команду из командной строки:
javac -d out -sourcepath src/main src/main/com/baeldung/flightrecorder/FlightRecorder.java
На этом этапе мы должны найти файл FlightRecorder.class в каталоге out/com/baeldung/flight recorder .
Теперь мы запустим программу со следующими опциями:
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=duration=200s,filename=flight.jfr -cp ./out/ com.baeldung.flightrecorder.FlightRecorder
5.3. Визуализация Данных
Теперь мы передаем файл flight.of в Java Mission Control , который является частью дистрибутива JDK. Это помогает нам визуализировать данные о наших событиях приятным и интуитивно понятным способом.
Его главный экран показывает нам информацию о том, как программа использовала процессор во время своего выполнения. Мы видим, что процессор был сильно загружен, что вполне ожидаемо из-за цикла while :
В левой части представления мы видим разделы Общие , Память , Код и Потоки , среди прочих. Каждый раздел содержит различные вкладки с подробной информацией. Например, вкладка Горячие методы раздела Код содержит статистику вызовов методов:
На этой вкладке мы можем обнаружить еще один недостаток нашего примера программы: метод java.util.ArrayList.grow(it) вызывался 17 раз, чтобы увеличить емкость массива каждый раз, когда не хватало места для добавления объекта.
В более реалистичных программах мы можем увидеть много другой полезной информации:
- статистика о созданных объектах, когда они были созданы и уничтожены сборщиком мусора
- подробный отчет о хронологии потоков, когда они были заблокированы или активны
- какие операции ввода-вывода выполняло приложение
6. Заключение
В этой статье мы познакомили вас с темой мониторинга и профилирования Java-приложения с помощью регистратора полетов Java. Этот инструмент остается экспериментальным, поэтому мы должны обратиться к его официальному сайту для получения более полной и свежей информации.
Как всегда, фрагмент кода доступен в нашем репозитории Github .