如何创建可重用的即时(持续时间)Java Flight Recorder JFR 事件?
Posted
技术标签:
【中文标题】如何创建可重用的即时(持续时间)Java Flight Recorder JFR 事件?【英文标题】:How to create a reusable instant (non-duration) Java FlightRecorder JFR event? 【发布时间】:2021-09-06 12:17:58 【问题描述】:我正在努力添加自定义飞行记录器事件以跟踪我们的一些 KPI,并通过飞行记录转储将它们暴露出来。
一个令我头疼的问题是如何将事件标记为基于“即时”或“持续时间”的事件。
https://docs.oracle.com/javacomponents/jmc-5-4/jfr-runtime-guide/about.htm#JFRUH171
从我有限的测试来看,似乎在您稍后重用的事件上调用 commit
(比如在 ThreadLocal 中)使得第二次和即将到来的对 commit
的调用包括结束时间戳和第二次提交和第一次提交之间的持续时间.
这并不真正适合我当前的用例,我对事件创建和提交调用之间的时间不感兴趣。
在我看来,如果你总是实例化新事件并省略调用 begin
你做构造一个没有持续时间的事件 - 但出于性能原因,我宁愿避免由每次生成新事件并限制堆分配。
【问题讨论】:
【参考方案1】:所有事件都是持续的,因为它们包含一个称为持续时间的字段。如果您调用commit()
而不调用begin()
或end()
,则持续时间将设置为0。它将在文件中为每个事件添加一个字节,并且开销可以忽略不计。在缓存和重用事件实例时,不支持,但在某些场景下可以工作。
推荐的方法是为每个事件创建一个对象。在大多数情况下,如果对象没有逃逸,JIT 能够消除分配。也就是把你正在使用事件对象的方法留在里面。
此视频描述了禁用事件的流程,但一些优化也适用于启用的事件。 https://youtu.be/plYESjZ12hM?t=1126
(Escape analysis 可能会随着时间的推移而改进,并且将来可能会使用 primitive objects。在线程本地缓存中可能会成为一种反模式,尤其是在 virtual threads 即将推出的情况下)
【讨论】:
谢谢基尔!来自 Mikael 的视频是我见过的对逃逸分析和死代码消除的最佳解释,如果涉及自定义事件,我会喜欢更多最佳实践示例。 2 个后续问题: - 大多数自定义事件示例设置可变字段,而不是传递给事件构造函数。这是由于 JIT 消除最佳实践还是它们可以互换? - JVM 内部事件似乎使用EventHandlers
而不是实例方法来构造/提交事件。这样做是出于性能原因吗?我们是否应该在性能关键代码中争取类似的东西?
设置字段而不是使用构造函数的一个原因是使用“if (event.shouldCommit()) event.x = foo() 来保护昂贵的操作(不能完全消除) ; ... " 在其他情况下,我不知道构造函数是否更快。当涉及到内部事件时,我们注意到 JIT 无法消除某些事件的分配(可能是由于异常处理)。 bugs.openjdk.java.net/browse/JDK-8187234 所以我们在 JDK 中有一些临时的 hack。
好的,这是保持构造函数精简的一个好点。我通过询问缓存的EventType
是否启用它并延迟构建事件来解决这个问题。以上是关于如何创建可重用的即时(持续时间)Java Flight Recorder JFR 事件?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Ionic 3 和 Angular 4 创建可重用组件