JProfiler帮助文档

垃圾回收器分析

理解和分析垃圾回收器(GC)的运行时特征非常重要,原因有几个。首先,GC 暂停可能会直接影响应用程序的响应能力。 通过了解垃圾回收器的运行表现,您可以优化其设置以减少这些暂停。 通常,频繁且耗时较长的 GC 周期可能表明堆过小,或者创建了过多的临时对象。

借助垃圾回收器探针 (probe),您可以解决这些问题,并在调优 JVM 设置时做出更明智的决策, 例如选择合适的垃圾回收器、堆大小或其他 JVM 参数。

垃圾回收器探针 (probe) 具有与其他探针 (probe) 不同的视图 (view),并且还使用不同的数据源。 它不是从 JVM 的 profiling 接口获取数据,而是使用 JFR 事件流 (stream) 来分析来自 JDK Flight Recorder 的 GC 相关事件。由于依赖于 JFR 事件流 (stream),仅当您在 HotSpot JVM 上对 Java 17 或更高版本进行分析 (profiled) 时,该 GC 探针 (probe) 才可用。当您打开 JFR 快照时,无论使用何种 Java 版本,都可以使用完全相同的探针 (probe)。

Garbage collections 视图 (view)

垃圾回收器探针 (probe) 中的主视图 (view) 是“Garbage collections”表格。它将所有记录的垃圾回收显示为行,并将其最重要的指标显示为列。

“Cause”列显示了触发 (trigger) 垃圾回收的原因。例如,调用 System.gc() 触发 (trigger) 了一次完整的垃圾回收(Full GC)。您可以从“Collector”列中关联的“G1Full”值中看到这一点。它还导致了长达 20 毫秒的严重暂停,这也是为什么通常不建议调用 System.gc()。其他原因会触发 (trigger) 年轻代空间回收(“G1New”)或 G1 回收器的混合 GC 回收(“G1Old”),后者用于清理老年代中未引用的对象。您可以看到,尽管年轻代回收清理的对象更多,但混合 GC 回收的耗时始终比年轻代回收更长。

经过特殊 GC 处理的被回收引用在单独的列中显示为“final”、“weak”、“soft”和“phantom”引用。

为最长暂停时间和暂停时间总和设置单独列的原因在于,每次垃圾回收都由多个产生单独暂停的阶段组成。此外,垃圾回收的“Duration”(持续时间)并不等于暂停时间总和,因为垃圾回收在执行期间仅部分暂停 JVM。您可以在屏幕截图中看到,“G1Old”回收的暂停时间仅占其总持续时间的约五分之一。

要检查垃圾回收的各个阶段,您可以切换“GC ID”列中的树形图标。

在上方的屏幕截图中,展开了 G1 回收器的混合 GC 回收(“G1Old”)。您可以看到大部分时间都花费在“Class Unloading”(类卸载)上,这并不会暂停 JVM。在右侧,您可以看到该垃圾回收的更多统计信息。在此处,已用堆保持不变,而已用 Metaspace 增加了 0.1%。

每个回收器的各个阶段各不相同。在上方的屏幕截图中显示了一次 Full GC。它花费了大量时间来标记整个堆中的存活对象。回收结束时,已用堆减少了 15.7%,而 Metaspace 保持不变。

在分析垃圾回收时,过滤是比较不同垃圾回收子集的重要工具。在表格顶部,有一个过滤器选择器,可让您选择任意列并配置相应的过滤器。查看相似垃圾回收的更简单方法是在表格上使用上下文菜单,并根据选定行中的列值选择过滤条件。

您可以添加多个过滤器来缩小感兴趣的垃圾回收范围。处于活动状态的过滤器在表格顶部显示为标签。也可以从嵌套的 GC 阶段表格中添加过滤器。

遥测 (telemetry)

GC 探针 (probe) 生成了许多遥测 (telemetry) 数据,这些数据可在“Telemetries”探针视图 (view) 中查看。

如果您关注最小化 GC 暂停时间,顶部的“Longest pause”遥测 (telemetry) 将是最值得关注的。您可以沿着遥测 (telemetry) 的时间轴拖动,以选择“Garbage Collections”视图 (view) 中的对应垃圾回收。为了获得更好的垂直分辨率,您可以从顶部的下拉列表中选择单个遥测 (telemetry),或者通过单击遥测 (telemetry) 的名称进行选择。

在上方的屏幕截图中,您可以看到随时间变化的暂停总和。JProfiler 通过构建记录数据的直方图来呈现可求和的度量值。Bin 宽度取决于可用的水平空间,因此直方图分箱(Bin)会根据缩放级别发生变化,如果启用了“适应窗口缩放(scale to fit)”,还会根据窗口宽度发生变化。保持不变的是所有直方图柱下方的总面积。

堆和 Metaspace 遥测 (telemetry) 基于展开垃圾回收时看到的统计数据。这意味着数据不会像完整分析会话 (session) 中的内存遥测 (telemetry) 那样定期采样。如果在某个时间段内没有发生垃圾回收,则不会有任何数据。对于分配 (allocation) 活动较少的 JVM,沿时间轴可能会有很长的区间,图形 (graph) 仅在两次垃圾回收之间进行插值。

这些遥测 (telemetry) 中的每一项都有两条数据线:“Before GC”和“After GC”。对于“Used Heap”遥测 (telemetry),差异通常很大。在任何时刻,您都可以通过比较两条数据线的值来查看垃圾回收完成了多少工作。您可以查看工具提示以获取精确数值。对于“Committed heap”遥测 (telemetry) 和 Metaspace 遥测 (telemetry),两条线之间的差异通常很小。

如果您正在分析 JFR 快照,来自 jdk.GCHeapSummary JFR 事件类型的相同数据也会用于遥测 (telemetry) 部分中的“Memory”遥测 (telemetry)。然而在这种情况下,“Before GC”和“After GC”的值都显示在同一条数据线上,并且数据不会像 GC 探针 (probe) 遥测 (telemetry) 中那样聚合到每秒一次的粒度,因此图形 (graph) 看起来会有所不同。

GC 摘要 (GC Summary)

GC 摘要显示了在整个记录周期内聚合的度量值。每个度量值都提供了垃圾回收的次数,以及平均值、最大值和总计值。顶部最重要的数据是直接影响应用程序活性 (liveness) 的“Pause times”(暂停时间)。

另一个顶级类别显示了所有回收的总时间,随后拆分为年轻代回收和老年代回收这两个子类别。

GC 配置 (GC Configuration)

在调优垃圾回收器时,您可能希望检查既可以显式设置也可以由垃圾回收器本身隐式设置的通用属性。

这些属性是所有垃圾回收器通用的,有助于您了解不同垃圾回收器之间的差异。

GC 标志 (GC Flags)

最后,特定于 GC 的标志让您了解垃圾回收器的哪些属性可以调优,并允许您检查它们的实际值。

“Origin”列显示了标志是如何设置的。“Default”值未脱离标准设置进行修改,而“Ergonomic”标志则由垃圾回收器自动调整。如果您在命令行上设置了特定的 GC 标志,其来源将报告为“Command line”。