自定义 JDK 飞行记录器事件 - 一口 Java

JDK 飞行记录器 (JFR) 是一款基于事件的分析工具,内置于 JDK 中。在默认设置下,JFR 的开销小于 1%,可用于在生产中跟踪 Java 运行时和应用程序的行为和性能,这对于解决生产错误或寻找性能优化机会很有用。

截至 JDK 18,已有 150 多种预定义的 JFR 事件类型,涵盖了诸如线程创建和删除、GC 暂停、内存分配等事件。这些事件提供了对 Java 运行时和应用程序操作的丰富而详细的视图。但是,在某些情况下,收集的数据可能存在空白,为此,JFR 还支持跟踪自定义事件类型。

创建和使用自定义 JFR 事件

要创建自定义 JFR 事件,请扩展 jdk.jfr.Event 类,如下例所示

import jdk.jfr.Event;

public class MyEvent extends Event {

}

要在应用程序中使用此事件,您需要初始化该事件,然后在要跟踪的代码周围调用 .being().commit(),如下所示

public void myMethod(){
	MyEvent myEvent = new MyEvent();
	myEvent.begin();
	
	//...do work here
	
	myEvent.commit();
}

目前捕获的唯一信息是 .begin().commit() 之间的执行时间和堆栈。但是,自定义事件可以捕获其他信息。

允许的 JFR 字段

允许自定义 JFR 事件具有 JFR 将收集的字段,但这些字段必须属于以下类型

  • byte
  • short
  • int
  • long
  • float
  • double
  • char
  • boolean
  • java.lang.String,可以为 null
  • java.lang.Thread,可以为 null
  • java.lang.Class,可以为 null

这些字段可以为应用程序中发生的情况提供其他上下文,例如,客户端输入的值、从其他系统返回的值或开发人员可能发现有用的其他信息。JFR 将静默忽略上述类型之外的字段。

JFR 注释

JFR 还提供注释来控制事件何时启用,或提供元数据。需要注意的关键注释包括

  • 类别:事件注释,以人类可读路径的格式将事件类型与类别关联。
  • 描述:使用一两句话描述元素的注释。
  • 已启用:事件注释,确定是否应默认启用事件。
  • 标签:为元素设置人类可读名称的注释(例如,“最大吞吐量”)。
  • 名称:设置元素默认名称的注释。
  • StackTrace:事件注释,确定事件默认情况下是否具有堆栈跟踪。
  • Threshold:事件注释,指定事件未记录的默认持续时间(例如,“20 毫秒”)。

其他注释

JFR 还预定义了其他一些注释

  • BooleanFlag:事件字段注释,指定该值是一个布尔标志,一个真或假值。
  • ContentType:元注释,指定注释表示内容类型,例如时间跨度或频率。
  • DataAmount:事件字段注释,指定值表示数据量(例如,字节)。
  • Experimental:指定元素是实验性的,可能会在不通知的情况下更改的注释。
  • Frequency:事件字段注释,指定该值是一个频率,以赫兹为单位测量。
  • MemoryAddress:事件字段注释,指定该值是一个内存地址。
  • MetadataDefinition:用于定义新类型的事件元数据的元注释。
  • Percentage:用于分数的事件字段注释,通常介于 0.0 和 1.0 之间,以指定该值是一个百分比。
  • Period:事件注释,指定周期性事件的默认设置值。
  • Registered:事件注释,用于编程事件注册。
  • Relational:用于关系注释的元注释,用于注释。
  • SettingDefinition:指定事件类中的方法应用于过滤事件的注释。
  • Timespan:事件字段注释,指定该值是一个持续时间。
  • Timestamp:事件字段注释,指定该值是一个时间点。
  • TransitionFrom:事件字段注释,指定事件从线程转换而来。
  • TransitionTo:事件字段注释,指定事件将很快转换到线程。
  • Unsigned:事件字段注释,指定该值是一个无符号数据类型。

配置 JFR 事件

预定义事件和自定义事件都可以使用 .jfc 文件或通过命令行进行配置。在 .jfc 文件中配置事件将如下所示

<configuration>
	...
	<event name="com.oracle.jfr.MyEvent">
   		<setting name="enabled">true</setting>
	</event>
	...
</configuration>

注意:如果未使用 @Name 标记,则事件的默认名称将是其完全限定名称。

事件也可以通过命令行进行配置,如下面的示例所示

-XX:StartFlightRecording=event-setting=<event-name>#<setting-name>=<value>

进一步阅读

有关 JDK Flight Recorder、其 API 或在应用程序中使用 JDK Flight Recorder 的更多信息,请务必查看以下链接

编码愉快!