Экосистема Java богата качественными инструментами для разработчиков, и средства профилирования и диагностики - не исключение.
Существуют коммерческие профилировщики, есть встроенные инструменты профилирования в ведущих IDE. А если вам важна свобода (или цена является важным фактором), open source сообщество также готово предложить достойные альтернативы.

Несмотря на удобство графических инструментов, работа из командной строки остаётся актуальной в моей практике.
Сценарий, в котором доступность диагностического функционала из консоли становится критичной, выглядит следующим образом:

  • Случилась проблема

  • Специалист получает доступ к консоли сервера

  • Надо оперативно провести диагностику и идентифицировать причину проблемы, используя инструменты доступные в этой консоли

Иногда нет даже непосредственного доступа к консоли, и нужно помочь инженеру поддержки выполнить диагностику в режиме “созвона”.

JFR (JDK Flight Recorder) - один из ключевых инструментов для диагностики работы Java приложений, который можно эффективно использовать из командной строки. Приёмам работы с этим инструментом я хочу посвятить данную статью.

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

Как правило, сценарий работы с JFR состоит из 3 этапов:

  • Запуск сессии JFR

  • Получение “записи” - бинарного файла событий

  • Анализ

Часто для анализа используется JDK Mission Control или другой графический инструмент. Но в данной статье мы пройдём по всем трём этапам, используя командную строку.

Запуск сессии JFR

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

Можно выделить следующие варианты запуска сессии:

  • На старте JVM через параметры запуска

  • Из локальной консоли используя jcmd

  • Удалённо через JMX протокол

  • Программно из кода приложения JVM

Далее я подробно разберу первые два способа.
Третий предполагает предварительную настройку JMX, что не тривиально технически и требует внимания к безопасности (зато позволяет подключить графические инструменты).
Четвертый может быть интересен для глубокой интеграции JFR в вашу архитектуру мониторинга.

Запуск сессии JFR на старте JVM

Ключевое достоинство JFR - это то, что его можно начать использовать на запущенном процессе JVM, даже если никаких специальных параметров при запуске процесса указано не было.

Однако возможность собирать диагностику с момента старта JVM может быть крайне полезна в определённых сценариях.

Для запуска сессии JFR на старте JVM используется ключ -XX:StartFlightRecording, за которым после двоеточия идут параметры, разделённые запятой.

java -XX:StartFlightRecording:delay=10s,filename=myrecording.jfr,settings=profile …

Так, пример команды выше запустит сессию через 10 секунд после старта JVM c настройками сбора событий “profile”.
Настройка сбора событий - это имя xml файла, описывающего, какие события должны быть включены в сессию и параметры их сбора. Есть два стандартных конфигурационных файла, которые находяться в JAVA_HOME/lib/jfr.

  • default.jfc - включает набор событий с низкими накладными расходами.

  • profile.jfc - включает существенно больше событий, размер результирующего файла растёт, а накладные расходы на их получение уже могут заметно влиять на приложение. Можно создать и собственную конфигурацию. К этому вопросу мы вернёмся чуть позже.

Исчерпывающую информацию по параметрам -XX:StartFlightRecording можно найти в статье “Управление Java Flight Recorder”.

Когда полезен запуск JFR на старте приложения?

  • Профилирование процесса запуска JVM и начальных этапов работы приложения (инициализации, прогрев кэшей и т.п.)

  • Старт “дежурной” сессии JFR

  • Профилирование процессов с ограниченным временем жизни

Запуск сессии JFR с помощью команды jcmd

jcmd - это универсальный инструмент JDK, позволяющий отправлять диагностические команды запущенному Java процессу, в том числе управлять работой JFR.

Ниже пример команды, позволяющей запустить JFR сессию с конфигурацией “profile” на 60 секунд.

jcmd 1234 JFR.start duration=60s filename=recording.jfr settings=profile
1234:
Started recording 1. The result will be written to:
 
/opt/demo/spring-petclinic/recording.jfr

Данная команда стартует сессию JFR, которая через 60 секунд автоматически завершится и дамп событий будет записан в файл с указанным именем.

Параметры, которые можно передать команде JFR.start, аналогичны параметрам опции -XX:StartFlightRecording, описанным выше.

Иногда вам нужно больше контроля над жизненным циклом JFR сессии. Для этого есть дополнительные команды.
Если не указывать параметр duration, сессия будет выполняться неопределенное время.

  • JFR.stop - позволяет остановить запущенную сессию.

  • JFR.dump - сохранить события в файл без остановки сессии.

  • JFR.check - посмотреть список активных сессий.

Ниже пример сессии профилирования через раздельный вызов команд JFR.start, JFR.dump и JFR.stop

Запуск сессии.

> jcmd 1234 JFR.start settings=profile
1234:
Started recording 2. No limit specified, using maxsize=250MB as default.
 
Use jcmd 1234 JFR.dump name=2 to copy recording data to file.

Дамп в файл.

> jcmd 1234 JFR.dump name=2 filename=recording2.jfr
1234:
Dumped recording "2", 309.6 kB written to:
 
/opt/demo/spring-petclinic/recording2.jfr

Останов сессии.

> jcmd 1234 JFR.stop name=2
1234:
Stopped recording "2".

Так как в этом случае мы не указали продолжительность сессии, если её не остановить, то она будет накапливать данные неопределенно долго. Но не нужно переживать, что JFR может “съесть” весь диск, лимит по умолчанию 250 МБ далее новые события будут замещать старые.

Управление настройками сессии

Выше мы использовали в качестве настроек стандартные пресеты. Однако часто возникает желание “подкрутить” настройки под себя.
При использовании Mission Control редактор настроек, который позволяет модифицировать индивидуальные настройки событий, доступен в момент запуска сессии JFR.
Похожая возможность есть и при запуске через командную строку.
Допустим мы хотим использовать конфигурацию profile, но при этом убрать сбор событий для исключений.
Это можно сделать, переопределив параметры для некоторых событий на старте сессии.

jcmd 1234 JFR.start duration=10s settings=profile jdk.JavaExceptionThrow#enabled=false

В примере мы выключили запись события для исключений.

Помимо точного указания идентификатора события, можно использовать его имя. Кроме того, есть ещё несколько полезных сокращенией.

Вот несколько примеров настроек событий.

jcmd 1234 JFR.start gc=high method-profiling=high

Групповые настройки, такие как gc и method-profiling определены в jfc файле (в данном случае JAVA_HOME/lib/jfr/default.jfc).

jcmd 1234 JFR.start com.example.UserDefined#enabled=true \
com.example.UserDefined#threshold=100/s

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

jcmd 1234 JFR.start +.UserDefined#enabled=true +.UserDefined#threshold=100/s

Тоже самое можно написать короче, используя шаблон с символом “+”.

Создание файлов настроек

Прямое управление параметрами сбора событий через строку запуска удобно для небольших изменений конфигурации JFR. Если вы уже определились с набором настроек и хотите использовать его повторно, стоит создать собственный JFC-файл (файл конфигурации JFR).
Обычно, для этого я пользуюсь графическим редактором в Mission Control, но команда jfr, входящая в состав JDK (как и jcmd), позволяет также редактировать jfc файлы из командной строки.

Например, скопируем конфигурацию “profile” и изменим параметры сэмплирования методов.

jfr configure --input profile.jfc \
jdk.CPUTimeSample#enabled=true --output /tmp/custom.jfc

Запустить сессию с настройками из файла можно следующей командой.

jcmd 1234 JFR.start duration=10s settings=/tmp/custom.jfc

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

Анализ данных JFR из командной строки

В результате манипуляций из предыдущей части мы тем или иным способом получаем файл с событиями JFR. Теперь нам нужно его проанализировать и прийти к каким-то выводам. Разумеется, для сложного анализа файл можно перенести на рабочую станцию и открыть в Mission Control, но это занимает время (и часто затруднено политиками безопасности).
Обработка файла событий прямо из командной строки, “не отходя от кассы”, даёт нам возможность быстро осуществить несложный анализ, чтобы сделать выводы о состоянии приложения.

Основной инструмент работы с файлами событий - команда jfr.
Эта команда позволяет распечатывать события в различных форматах.

> jfr print recording.jfr
jdk.SafepointBegin {
  startTime = 04:00:38.849 (2025-10-31)
  duration = 0.00913 ms
  safepointId = 3409
  totalThreadCount = 33
  jniCriticalThreadCount = 0
  eventThread = "VM Thread" (osThreadId = 45423)
}
 
jdk.ObjectAllocationSample {
  startTime = 04:00:38.850 (2025-10-31)
  objectClass = java.lang.String (classLoader = bootstrap)
  weight = 86.3 kB
  eventThread = "C1 CompilerThread0" (javaThreadId = 22)
}
...
jfr print –json recording.jfr
{
  "recording": {
    "events": [{
      "type": "jdk.SafepointBegin",
      "values": {
        "startTime": "2025-10-31T04:00:38.849436842+03:00",
        "duration": "PT0.000009131S",
        "eventThread": {
          "osName": "VM Thread",
          "osThreadId": 45423,
          "javaName": null,
          "javaThreadId": 0,
          "group": null,
          "virtual": false
    	},
    	"safepointId": 3409,
    	"totalThreadCount": 33,
    	"jniCriticalThreadCount": 0
  	}
  }, { 
...

Один из доступных форматов - JSON, что позволяет передать данные JFR на вход традиционных инструментов анализа данных. Мне удобно пользоваться jq.

При диагностике, я первым делом смотрю на использование ресурсов ЦПУ.

  • Сколько ЦПУ потребляет процесс?

  • Сколько ЦПУ потребляет сборщик мусора?

  • Какие потоки потребляют больший процент ЦПУ?

С помощью jq, популярной утилиты для работы с JSON, дамп JFR позволяет ответить на все эти вопросы!

> jfr print --json --events ThreadCPULoad myrecording.jfr | jq '
[.recording.events[]
  | select(.type == "jdk.ThreadCPULoad")
  | {
      javaName: .values.eventThread.javaName, 
      user: .values.user, 
      system: .values.system} ]
  | group_by(.javaName)
  | map({
    javaName: .[0].javaName,
    user: (map(.user) | add),
    system: (map(.system) | add)
  }) | sort_by(-.user)'

[
  {
	"javaName": "C2 CompilerThread1",
	"user": 1.4746960910000002,
	"system": 0.0628239843
  },
  {
	"javaName": "C2 CompilerThread0",
	"user": 0.27601727600000003,
	"system": 0.00119408049
  },
  {
	"javaName": "C1 CompilerThread0",
	"user": 0.11426830399999999,
	"system": 0.00334142412
  },
  {
	"javaName": "DestroyJavaVM",
	"user": 0.029225044,
	"system": 0.0012193053
  },
  {
	"javaName": "http-nio-8080-exec-8",
	"user": 0.0218696855,
	"system": 0.0008536230300000001
  },
...

До недавнего времени использование jq (или другого стороннего инструмента) было необходимо, поскольку команда jfr позволяла только распечатать события. Однако, начиная с JDK 21, стала доступна подкоманда jfr view, позволяющая строить типовые отчёты по файлам событий JFR.

Например, чтобы получить сводку об использовании ЦПУ процессом, можно использовать отчёт cpu-load.

> jfr view cpu-load recording.jfr

CPU Load Statistics
-------------------
 
JVM User (Minimum): 0.00%
 
JVM User (Average): 0.08%
 
JVM User (Maximum): 0.40%
 
JVM System (Minimum): 0.00%
 
JVM System (Average): 0.00%
 
JVM System (Maximum): 0.07%
 
Machine Total (Minimum): 0.00%
 
Machine Total (Average): 0.15%
 
Machine Total (Maximum): 0.65%

Для оценки накладных расходов сборщика мусора gc-cpu-time

> jfr view gc-cpu-time recording.jfr

GC CPU Time
-----------
 
GC User Time: 1.94 s
 
GC System Time: 150 ms
 
GC Wall Clock Time: 920 ms
 
Total Time: 56.0 s
 
GC Count: 235

Сводка использования CPU по потокам: thread-cpu-load

jfr view thread-cpu-load recording.jfr

                            	Thread CPU Load
 
Thread                                                         	System  User
------------------------------------------------------------------ ------ -----
C2 CompilerThread2                                              	0.18% 1.27%
C2 CompilerThread1                                              	0.17% 1.20%
http-nio-8080-exec-7                                            	0.01% 0.25%
http-nio-8080-exec-3                                            	0.00% 0.24%
http-nio-8080-exec-12                                           	0.00% 0.22%
http-nio-8080-exec-10                                           	0.00% 0.22%
http-nio-8080-exec-14                                           	0.01% 0.22%
http-nio-8080-exec-2                                            	0.01% 0.22%
http-nio-8080-exec-15                                           	0.02% 0.20%
http-nio-8080-exec-1                                            	0.01% 0.20%
http-nio-8080-exec-11                                           	0.02% 0.20%
C2 CompilerThread0                                              	0.00% 0.17%
http-nio-8080-exec-4                                            	0.00% 0.16%
http-nio-8080-exec-8                                            	0.00% 0.16%
http-nio-8080-Poller                                            	0.01% 0.03%
...

В примере выше стоит помнить, что 100% считается от всех ядер в системе. Например, если в системе 8 ядер, максимальное потребление, которого может достичь один поток - 100% / 8 = 12.5%.

Если вы не уверены сколько ядер в системе, эта информация также доступна в дампесобытий JFR.

> jfr view system-information recording.jfr

System Information
------------------
 
Total Physical Memory Size: 7.4 GB
 
OS Version: DISTRIB_ID=Ubuntu DISTRIB_RELEASE=24.04 DISTRIB_CODENAME=noble DIST
        	RIB_DESCRIPTION="Ubuntu 24.04.1 LTS" uname: Linux 5.15.146.1-micros
        	oft-standard-WSL2 #1 SMP Thu Jan 11 04:09:03 UTC 2024 x86_64 libc:
        	glibc 2.39 NPTL 2.39
 
Virtualization: Hyper-V virtualization
 
CPU Type: Intel (null) (HT) SSE SSE2 SSE3 SSSE3 SSE4.1 SSE4.2 Core Intel64
 
Number of Cores: 8
 
Number of Hardware Threads: 14
 
Number of Sockets: 1
 
CPU Description: Brand: Intel(R) Core(TM) Ultra 5 125U, Vendor: GenuineIntel Fa
             	mily: <unknown> (0x6), Model: <unknown> (0xaa), Stepping: 0x4
             	Ext. family: 0x0, Ext. model: 0xa, Type: 0x0, Signature: 0x000
             	a06a4 Features: ebx: 0x09100800, ecx: 0xfeda3203, edx: 0x1f8bf
             	bff Ext. features: eax: 0x00000000, ebx: 0x00000000, ecx: 0x00
             	000121, edx: 0x2c100800 Supports: On-Chip FPU, Virtual Mode Ex
             	tensions, Debugging Extensions, Page Size Extensions, Time Sta
             	mp Counter, Model Specific Registers, Physical Address Extensi
             	on, Machine Check Exceptions, CMPXCHG8B Instruction, On-Chip A
             	PIC, Fast System Call, Memory Type Range Registers, Page Globa
             	l Enable, Machine Check Architecture, Conditional Mov Instruct
             	ion, Page Attribute Table, 36-bit Page Size Extension, CLFLUSH
              	Instruction, Intel Architecture MMX Technology, Fast Float Po
             	int Save and Restore, Streaming SIMD extensions, Streaming SIM
             	D extensions 2, Self-Snoop, Hyper Threading, Streaming SIMD Ex
             	tensions 3, PCLMULQDQ, Supplemental Streaming SIMD Extensions
             	3, Fused Multiply-Add, CMPXCHG16B, Process-context identifiers
             	, Streaming SIMD extensions 4.1, Streaming SIMD extensions 4.2
             	, MOVBE, Popcount instruction, AESNI, XSAVE, OSXSAVE, AVX, F16
             	C, LAHF/SAHF instruction support, Advanced Bit Manipulations:
             	LZCNT, SYSCALL/SYSRET, Execute Disable Bit, RDTSCP, Intel 64 A
             	rchitecture, Invariant TSC

jfr view включает широкий набор готовых отчётов, позволяющих быстро проверять гипотезы о возможных причинах проблем.

Ниже список очётов, доступных в JDK 25

Java virtual machine views:
 blocked-by-system-gc  	    gc-concurrent-phases  jvm-information
 class-modifications   	    gc-configuration      longest-compilations
 compiler-configuration	    gc-cpu-time           native-memory-committed
 compiler-phases       	    gc-parallel-phases    native-memory-reserved
 compiler-statistics   	    gc-pause-phases       safepoints
 deoptimizations-by-reason  gc-pauses             tlabs
 deoptimizations-by-site    gc-references         vm-operations
 gc                    	    heap-configuration
 
Environment views:
 active-recordings         cpu-load           	  native-library-failures
 active-settings           cpu-load-samples  	  network-utilization
 container-configuration   cpu-tsc           	  recording
 container-cpu-throttling  environment-variables  system-information
 container-cpu-usage  	   events-by-count   	  system-processes
 container-io-usage   	   events-by-name    	  system-properties
 container-memory-usage    jvm-flags
 
Application views:
 allocation-by-class        	exception-by-site 	  method-timing
 allocation-by-site         	exception-by-type 	  modules
 allocation-by-thread       	exception-count   	  monitor-inflation
 class-loaders              	file-reads-by-path	  native-methods
 contention-by-address      	file-writes-by-path   object-statistics
 contention-by-class        	finalizers        	  pinned-threads
 contention-by-site         	hot-methods       	  socket-reads-by-host
 contention-by-thread       	latencies-by-type 	  socket-writes-by-host
 cpu-time-hot-methods       	longest-class-loading thread-allocation
 cpu-time-statistics        	memory-leaks-by-class thread-count
 deprecated-methods-for-removal memory-leaks-by-site  thread-cpu-load
 exception-by-message       	method-calls      	  thread-start

Помимо перечисленных отчётов можно указать идентификатор JFR события, чтобы распечатать события в табличной форме.

> jfr view --width 80 jdk.ThreadStart recording.jfr
 
                            	Java Thread Start
 
Time 	Event Thread  	Stack Trace   	New Java Thread   Parent Java Th...
-------- ----------------- ----------------- ----------------- -----------------
04:48:00 http-nio-8080-... org.apache.tom... http-nio-8080-... http-nio-8080-...
04:48:03 C2 CompilerThr... N/A           	C2 CompilerThr... C2 CompilerThr...
04:48:05 C2 CompilerThr... N/A           	C2 CompilerThr... C1 CompilerThr...
04:48:05 C2 CompilerThr... N/A           	C2 CompilerThr... C1 CompilerThr...
04:48:06 C2 CompilerThr... N/A           	C2 CompilerThr... C1 CompilerThr...
04:48:06 C2 CompilerThr... N/A           	C2 CompilerThr... C1 CompilerThr...
04:48:06 HikariPool-1:c... java.lang.Syst... HikariPool-1:c... http-nio-8080-...

Приведу ещё несколько примеров отчётов команды jfr view.

thread-allocation - позволяет получить топ потоков по интенсивности аллокации памяти

> jfr view thread-allocation recording.jfr
 
                      	Thread Allocation Statistics
 
Thread                                                 	Allocated Percentage
---------------------------------------------------------- --------- ----------
http-nio-8080-exec-12                                     	9.6 GB 	10.30%
http-nio-8080-exec-7                                      	9.4 GB 	10.08%
http-nio-8080-exec-3                                      	9.4 GB 	10.05%
http-nio-8080-exec-4                                      	9.3 GB  	9.97%
http-nio-8080-exec-10                                     	9.3 GB  	9.97%
http-nio-8080-exec-1                                      	9.3 GB  	9.96%
http-nio-8080-exec-11                                     	9.0 GB  	9.62%
http-nio-8080-exec-2                                      	8.9 GB  	9.53%
http-nio-8080-exec-8                                      	8.9 GB  	9.49%
http-nio-8080-exec-14                                     	8.8 GB  	9.40%
http-nio-8080-exec-15                                     	1.3 GB  	1.43%
Notification Thread                                      	89.2 MB  	0.09%

Также можно посмотреть точки интенсивной аллокации

> jfr view --width 80 allocation-by-site recording.jfr
 
                           	Allocation by Site
 
Method                                                  	Allocation Pressure
----------------------------------------------------------- -------------------
org.apache.tomcat.util.http.parser.Host.parse(MessageBytes)          	76.72%
org.springframework.web.util.pattern.PathPattern.matches...           	8.50%
java.util.Arrays.copyOfRange(byte[], int, int)                        	1.53%
jdk.internal.misc.Unsafe.allocateUninitializedArray(...)              	1.22%
sun.util.calendar.Gregorian.newCalendarDate(TimeZone)                 	0.61%
java.util.HashMap.newNode(...)                                        	0.52%
org.hibernate.engine.internal.StatefulPersistenceContext...           	0.51%
org.springframework.core.ResolvableType.forType(...)                  	0.45%
java.util.TimeZone.clone()                                            	0.43%
java.lang.invoke.DirectMethodHandle.allocateInstance(...)             	0.36%
org.thymeleaf.engine.Model.<init>(...)                                	0.35%
java.lang.StringLatin1.newString(byte[], int, int)                    	0.33%
java.util.Arrays.copyOf(Object[], int)                                	0.31%
sun.util.calendar.AbstractCalendar.getCalendarDate(...)               	0.28%
org.springframework.boot.loader.net.protocol.jar.JarUrlC...           	0.28%
org.hibernate.engine.internal.EntityEntryContext.addEnti...           	0.27%
jdk.internal.loader.URLClassPath$Loader.findResource(...)             	0.26%

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

> jfr view exception-by-type recording.jfr
 
       	Exceptions by Type
 
Class                          	Count
--------------------------------- ------
java.io.EOFException             	189
java.lang.ClassNotFoundException   	2

Несмотря на богатство отчётов, стоит признать, что табличные представления jfr view достаточно поверхностны, у них отсутствуют возможности фильтрации (например, часто хочется отсечь нерелевантные потоки) и полноценным инструментом анализа эту команду назвать сложно.
Тем не менее, возможность быстро получить сводки по дампу JVM крайне удобна на практике и сокращает число “jq заклинаний”, которые надо держать под рукой.

Получение сводки событий JFR прямо с JVM

В начале статьи я писал про 3 шага работы с JFR

  • Сбор событий

  • Запись дампа

  • Анализ

Но это ещё не все. Начиная с JDK 15 события JFR можно получать с минимальными задержками через потоковый API. А в JDK 21, jcmd пополнилась командой JFR.view, полностью аналогичной консольной команде jfr view, которая строит отчёты по событиям собранным в рамках активных сессий без необходимости записи их в файл.

Конечно, JFR.view не подходит для глубокого анализа, однако она позволяет быстро оценить состояния JVM.

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

> jcmd 1234 JFR.view events-by-count
1234:
 
  Event Types by Count (Experimental)
 
Event Type                    	Count
--------------------------------- -----
Native Sample                 	1,831
Boolean Flag                    	494
Recording Setting               	379
Long Flag                       	137
Java Thread Park                	125
Unsigned Long Flag               	92
Java Thread Statistics           	51
Class Loading Statistics         	51
CPU Load                         	51
Compiler Statistics              	51
Exception Statistics             	51
Resident Set Size                	51
Thread CPU Load                  	50
...
TLAB Configuration                	1
GC Configuration                  	1
 
Timespan: 04:51:47 - 05:01:47

Заключение

В своей работе я всегда ценил возможность провести диагностику работы JVM из командной строки. Даже написал для этого собственный минималистичный профайлер - SJK.
JDK Flight Recorder начинал с парадигмы: собрать (инструментация JVM) -> доставить (самодостаточный файл) -> проанализировать (на рабочем месте эксперта).
На ранних этапах своего развития он не очень подходил для сценариев работы из консоли.

С тех пор он прошёл серьёзный путь: jcmd позволила управлять работой JFR из командной строки, a команда jfr - проводить базовый анализ и экспортировать данные в JSON. Также нужно отметить богатство сигналов/событий собираемых JFR, число которых растёт с каждым релизом.

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

Больше экспертных статей, событий и новостей из мира Java можно найти в тг-канале Axiom JDK.

Комментарии (0)