JFR 事件流停止 - Sip of Java
Billy Korando 于 2023 年 4 月 24 日发布
JDK 20 的发布为 JDK Flight Recorder (JFR) 带来了多项更新。最重大的变化是针对事件流 API。我们来看看这些变化以及如何在应用程序中使用它们。
新的 JFR 事件
与每次 JDK 发布一样,都会添加一些新的 JFR 事件,而 JDK 20 也不例外。添加了三个新的 JFR 事件,使预定义事件的总数达到 177。添加的事件为
- jdk.InitialSecurityProperty (JDK-8292177)
- jdk.SecurirtyProviderService (JDK-8294239)
- jdk.JITRestart (JDK-8289524)
stop()
已添加到 JFR 事件流 API
JFR 事件流 API 在 JDK 14 中添加,随附 JEP 349。JFR 事件流 API 提供多项有价值的功能:对 JFR 事件的编程访问、应用程序和 JVM 内部近乎实时的视图,以及在自动化测试中使用 JFR 的能力。新 .stop()
方法将在最后一个项目中看到特别的优势。要了解 .stop()
的优势,让我们先回顾一下如何在 JDK 19 及更早版本中使用 JFR 进行自动化测试。
在 JDK 20 之前进行自动化测试中的 JFR
虽然 JFR 可以用于自动化测试,但它并不是非常直接,而且会产生很多视觉噪音,如下面的示例所示
虽然在自动化测试中使用 JFR 有很多不同的途径,但上面的示例在最大程度缩短测试执行时间的同时,确保捕获开发人员正在寻找的 JFR 事件,是最有效的途径之一。不过,此示例会产生很多视觉噪音,并且不直接。
信号事件
其中一个最令人烦恼的部分是开发人员需要创建一个“信号”事件,用作测试中关闭流的信号。在上面的示例中,这是通过 TestEvent
完成的。此事件的唯一目的是在被测试的代码执行完毕时发出信号,这可以通过 testEvent.commit();
行在被测试的方法之后看到;sampleApplication.doStuff();
。
关闭流
信号事件 TestEvent
的另一个目的是触发关闭 JFR 流,这通过 rs.onEvent("TestEvent", e -> rs.close());
行完成。这本质上是在告诉流,当 TestEvent
添加到流时关闭。
暂停执行
需要发出信号事件并关闭流,因为事件不会在发生时立即写入 JFR 事件流中。这就是我之前使用“接近实时”这个词组的原因,因为事件大约每秒才会刷新到流中一次。但是,这并不能保证,因为 JFR 事件流可能会因等待系统资源或只是有许多事件要写入而被阻塞。因此,一个简单的 Thread.sleep()
无法可靠地工作。相反,rs.awaitTermination();
用于暂停测试执行,直到流被 rs.onEvent("TestEvent", e -> rs.close());
关闭。
实际上,这通常会使测试执行时间增加大约一秒。单独来看,这并不意味着什么,但如果在许多自动化测试中使用了 JFR,那么这些额外的几秒钟会显著增加测试套件的执行时间。
幸运的是,使用 stop()
,这一切都已成为过去。
使用 .stop()
的极大简化
使用 .stop()
编写的与上述示例等效的自动化测试如下所示
除了极大简化测试编写、无需发出关闭 JFR 流的信号事件以及暂停执行以等待流关闭的明显好处之外,测试执行速度也大大提高了。当调用 rs.stop()
时,这会立即将所有事件刷新到流中并关闭流。测试不再需要暂停大约一秒钟来等待事件刷新。
延伸阅读
InitialSecurityProperty JFR 事件(JBS 问题)
发行说明:新 JFR 事件:jdk.SecurityProviderService(JBS 问题)
添加 JFR JIT 重启事件(JBS 问题)
编码愉快!