JFR快照中的视图
除了JFR事件浏览器外,JProfiler使用了一些可用于完整分析会话的视图,使用JFR数据 填充。之所以可以这样做,是因为JFR收集了内存分配和方法执行的数据。主要的限制是,记录速率低,因此获取足够的数据来查看有问题的热点可能 需要很长时间。
遥测
除了“已记录对象的遥测”外,完整分析会话中的所有遥测也可以在JFR快照中使用,但在显示的数据方面存在一些限制。内存遥测不会显示 GC相关的池,线程遥测不会显示按线程状态分类的线程计数,记录的吞吐量遥测显示大小而不是对象计数而且不显示正在被释放的对象。
下面的表格显示了被各种遥测使用的事件类型,以及他们是否在“默认(default)”和“分析(profile)”模板中被启用。
遥测 | 事件类型 | 在分析中被启用 |
---|---|---|
内存 | jdk.GCHeapSummary, jdk.MetaspaceSummary | 全部 |
记录的吞吐量 | jdk.ObjectAllocationSample, jdk.ObjectAllocationInNewTLAB, jdk.ObjectAllocationOutsideTLAB | 仅分析(profile) |
GC活动 | jdk.GarbageCollection | 全部 |
类 | jdk.ClassLoadingStatistics | 全部 |
线程 | jdk.JavaThreadStatistics | 全部 |
CPU负载 | jdk.CPULoad | 全部 |
内存视图
在“内存”部分,使用两种不同的事件类型来填充视图数据。“活动对象视图向你展示了,一次完整的垃圾回收后留在堆上的所有类和实例计数统计。
该数据只有在启用了jdk.ObjectCount
事件才可用,而默认(default)JFR模板没有启用该事件,因为它会带来很大的开销。
你也可以在高级JFR配置中使用“垃圾回收器”下拉菜单切换此设置。在 Java 17 之前,这个下拉菜单的标签是“内存分析”。
如果快照中不止一次记录了jdk.ObjectCount
事件,该视图会显示jdk.ObjectCount
第一次出现
和最后一次的差异。这样的话,你可以了解到在记录期间数值发生了什么变化,并可能为内存泄漏提供一些线索。如果这些时间不与快照记录
的开始和结束点重合,遥测视图中会添加相应的书签。只有总对象大小超过一个固定阈值(通常是堆大小的1%)的类才会被包括进来。
对于任何重要的调查,考虑使用一个完整的分析会话,或生成一个 HPROF快照。
“已记录的对象视图和分配视图,从Java16开始显示”来自jdk.ObjectAllocationSample
事件的数据,在更早的Java版本中显示来自
jdk.ObjectAllocationInNewTLAB
和jdk.ObjectAllocationOutsideTLAB
事件的数据。高级UI中的
“分配分析”下拉列表也提供了一种方式来启用这些事件类型。
与“活动视图”相反,他们仅显示记录被激活时分配的对象。分配(Allocations)是由JFR采样得到的,但是报告的大小是对总分配大小的估算 由于这种不一致性,这些视图中报告的大小,与采样计数乘以实例平均大小并不对应。不然的话,这些视图与 完整分析会话中的内存视图有类似的功能。
CPU视图
“CPU视图”包含调用树、热点视图和调用图。“Runnable”线程状态中的数据是根据jdk.ExecutionSample
事件得到的,
该事件在两个标准JFR模板中默认都有记录。但是,默认情况下,采样率被设置为20ms,与JFR高级UI中“方法采样”设置的“常规”选项对应。
考虑到JFR只采样非常少量的随机线程,要获取足够的数据让热点足够明显,可能需要很长时间。如果有必要,考虑降低jdk.ExecutionSample
的周期。请记住,这可能会让快照变得非常大,因为JFR不累积数据。
由于线程采样是零星断断续续的,因此无法估算例如在完整分析会话中的执行时间。调用树和热点视图中显示的是事件计数而不是时间。 这和异步采样类似,有相同的缺点。其他线程状态“等待(Waiting)”、“阻塞(Blocking)”和 “Socket与文件I/O”依然测量时间。由于这种不一致性,线程状态选择器中的“所有线程状态”模式不可用。
另一个需要考虑的是,不可运行线程状态是根据具有可配置最小持续时间阈值的事件计算出来的,这些阈值显示在线程状态选择器旁边的工具提示中。 这些线程状态的实际总时间有可能大的多。用于组装线程状态的事件类型表如下所示:
线程状态 | 事件类型 |
---|---|
可运行(Runnable) | jdk.ExecutionSample |
等待(Waiting) | jdk.JavaMonitorWait, jdk.ThreadSleep, jdk.ThreadPark |
阻塞(Blocking) | jdk.JavaMonitorEnter |
Socket和文件I/O | jdk.SocketRead, jdk.SocketWrite, jdk.FileRead, jdk.FileWrite |
该视图的功能在CPU视图的帮助主题中有介绍。 注意,完整分析会话中的许多功能在JFR语境(context)下不可用。
线程和Monitor视图
根据按事件顺序排列的方法采样数据,可以计算出线程历史视图,包括显示等待(waiting)和阻塞(blocking)时间堆栈跟踪的 工具提示。
线程转储是JFR和JProfiler中都有的一项功能,会在相同视图中显示。在这种情况下,事件浏览器不能替代,因为它无法显示
jdk.ThreadDump
事件的线程转储列的结构化内容。在线程转储视图,你也可以
比较不同的线程转储。
通过jdk.JavaMonitorWait
、jdk.ThreadSleep
和jdk.ThreadPark
事件,JProfiler计算出一个与完整分析会话类似的监控(Monitor)历史,只是没有
阻塞线程的历史。如果你需要这些信息来解决你的问题,请切换到一个完整的分析会话。这也意味着来自于完整分析会话的锁状态图
对于JFR快照不可用。显示等待事件聚合信息的,Monitor使用统计信息会被呈现,并且只显示等待时间。
探针
完整分析会话中的一些JVM探针,在JFR快照中有等效的数据源。他们和事件浏览器相比,主要优势是他们会将相关事件类型合并。 下面的表格中显示了可用探针和作为他们的数据源的事件类型。
探针 | 事件类型 | 在分析(profile)中被启用 |
---|---|---|
Sockets | jdk.SocketRead, jdk.SocketWrite | 所有 |
文件 | jdk.FileRead, jdk.FileWrite | 所有 |
类 | jdk.ClassLoad, jdk.ClassUnload, jdk.ClassDefine | 无 |
异常 | jdk.JavaErrorThrow, jdk.JavaExceptionThrow | 错误(Error)/所有,异常(Exception)/无 |
垃圾回收器 | jdk.GarbageCollection, jdk.GCPhasePause, jdk.YoungGarbageCollection, jdk.OldGarbageCollection, jdk.GCReferenceStatistics, jdk.GCPhasePauseLevel<n>, jdk.GCHeapSummary, jdk.MetaspaceSummary, jdk.GCHeapConfiguration, jdk.GCConfiguration, jdk.YoungGenerationConfiguration, jdk.GCSurvivorConfiguration, jdk.GCTLABConfiguration | 所有 |
类加载在高级JFR UI中有一个单独的复选框,用于打开所有三个类加载事件。
每个探针显示多个视图。和事件浏览器相反,其聚焦点是聚合数据,而不是单个事件。这也是JProfiler中的探针在概念上与JFR 数据收集不同的地方。
除了垃圾回收器探针,所有探针都有下列视图: 调用树和热点视图允许你选择单个线程或线程组,以及一个聚合级别。默认情况下,会显示所有线程以及其聚合级别是“方法”。
遥测视图显示,记录数据中的一个或多个遥测,和一个一次性显示他们所有的概览页面。完整的遥测可以通过点击遥测名称打开。 通过沿着时间轴拖拽,你可以在事件视图中选择对应的事件。
事件视图和JFR浏览器中的类似。但是,它显示与底层JFR事件像对应的多种事件类型,并且提供了一个类型选择器。单选和多选的,过滤和堆栈跟踪 显示的处理方式和事件浏览器中一样。还有时间和内存测量的直方图视图,你可以通过沿着横轴拖拽来选择范围。
垃圾回收器视图有些特殊,因为在使用Java 17或更高版本的分析会话中,完整分析会话可以显示完全相同的信息。 当记录JVM探针分类下的垃圾回收器探针时,JFR流用于获取必要的数据。查看垃圾回收器分析 章节获取更多信息。