理解和分析垃圾回收器(GC,Garbage Collector)的运行时特性非常重要,原因有很多。首先,GC暂停会直接影响应用程序的响应速度。 通过了解垃圾回收器的运行情况,可以优化其设置,从而减少这些暂停。通常,频繁且耗时较长的GC周期可能意味着堆空间过小,或者创建了过多的临时对象。
借助垃圾回收器探针(probe),你可以解决这些问题,并在调整JVM设置(如选择合适的垃圾回收器、堆大小或其他JVM参数)时做出更明智的决策。
垃圾回收器探针拥有与其他探针不同的视图(view),并且使用不同的数据源。 它不是通过JVM的profiling接口获取数据,而是利用JFR流(JFR streaming)分析GC相关事件,数据来源于 JDK Flight Recorder。由于依赖JFR事件流,GC探针仅在你分析Java 17或更高版本的HotSpot JVM时可用。 当你打开JFR快照时,无论Java版本如何,都可以使用完全相同的探针。
垃圾回收视图
垃圾回收器探针的主视图是“垃圾回收(Garbage collections)”表。该表以行的形式展示所有记录到的垃圾回收,每一列显示其最重要的指标。
“原因(Cause)”列显示了触发垃圾回收的原因。例如,调用System.gc()会触发一次完整的垃圾回收。
你可以在“Collector”列看到对应的“G1Full”值。该操作还导致了20毫秒的明显暂停,因此通常不建议调用System.gc()。
其他原因会触发新生代空间的回收(“G1New”),或者G1回收器的老年代GC(“G1Old”),用于清理老年代中未被引用的对象。
你可以看到,老年代GC的耗时通常比新生代GC更长,尽管新生代GC回收了更多对象。
具有特殊GC处理的被回收引用会以“final”、“weak”、“soft”和“phantom”引用的形式显示在单独的列中。
之所以有“最长暂停”和“暂停总和”两个单独的列,是因为每次垃圾回收由多个阶段组成,每个阶段会产生独立的暂停。 此外,垃圾回收的“持续时间(Duration)”并不等于暂停总和,因为垃圾回收在执行时只会部分暂停JVM。 你可以看到,截图中的“G1Old”回收仅暂停了大约五分之一的持续时间。
若要检查垃圾回收的各个阶段,可以在“GC ID”列切换树形图标。
在上面的截图中,G1回收器的混合GC(“G1Old”)已展开。你可以看到,大部分时间都花在了“Class Unloading”阶段,该阶段不会暂停JVM。 在右侧,你可以看到该垃圾回收的更多统计信息。此处,已用堆空间保持不变,而已用元空间(metaspace)上升了0.1%。
每种回收器的阶段都不同。上图展示了一次完整回收(full collection)。它花费大量时间在整个堆上标记存活对象。 回收结束时,已用堆空间减少了15.7%,而元空间保持不变。
在分析垃圾回收时,过滤(filtering)是比较不同垃圾回收子集的重要工具。在表格顶部有一个过滤器选择器,你可以选择任意列并配置相应的过滤条件。 更简单的方式是在表格的上下文菜单中,基于所选行的列值直接选择过滤条件,以便快速查看类似的垃圾回收。
你可以添加多个过滤器,进一步缩小关注的垃圾回收范围。激活的过滤器会以标签的形式显示在表格顶部。也可以在嵌套的GC阶段表中添加过滤器。
遥测(Telemetries)
GC探针会生成多个遥测(telemetry),可在“遥测(Telemetries)”探针视图中查看。
如果你关注如何最小化GC暂停,顶部的“最长暂停(Longest pause)”遥测将最为关键。你可以在遥测的时间轴上拖动,选中对应的垃圾回收,在“垃圾回收(Garbage Collections)”视图中查看。 为了获得更好的纵向分辨率,可以在顶部下拉菜单中选择单个遥测,或直接点击遥测名称。
上图展示了随时间变化的暂停总和。JProfiler通过构建记录数据的直方图(histogram)来展示可累加的度量。 直方图的分箱宽度取决于可用的水平空间,因此缩放级别变化或启用“scale to fit”时,分箱会相应调整。 不变的是所有直方图分箱下的总面积。
堆和元空间遥测(heap and metaspace telemetries)基于你展开垃圾回收时看到的统计数据。 这意味着数据不像完整profiling会话中的内存遥测那样定期采样。如果某个时间段内没有发生垃圾回收,则不会有数据。 对于分配活动较少的JVM,时间轴上可能会有较长的区间,图形仅在两次垃圾回收之间插值显示。
每个遥测都有两条数据线:“GC前(Before GC)”和“GC后(After GC)”。 对于“已用堆(Used Heap)”遥测,这两者的差异通常很大。你可以通过比较两条数据线的数值,了解每次垃圾回收完成了多少工作。 鼠标悬停在数据点上可查看精确数值。对于“已提交堆(Committed heap)”遥测和元空间遥测,两条线之间的差异通常较小。
如果你正在分析JFR快照,则“内存(Memory)”遥测部分也会使用jdk.GCHeapSummary
JFR事件类型中的相同数据。
但在这种情况下,“GC前(Before GC)”和“GC后(After GC)”的数值会显示在同一条数据线上,且数据不会像GC探针遥测那样按每秒一次的粒度聚合,因此图形会有所不同。
GC摘要(GC Summary)
GC摘要展示了整个记录期间的聚合度量。每个度量项都提供了垃圾回收次数,以及平均值、最大值和总值。 最重要的数据在顶部,即“暂停时间(Pause times)”,它们会直接影响应用程序的活性(liveness)。
另一个顶级类别展示了所有回收的总耗时,并进一步细分为新生代和老年代回收的两个子类别。
GC配置(GC Configuration)
在调整垃圾回收器时,你可能需要查看那些可以显式设置或由垃圾回收器隐式设置的常用属性。
这些属性适用于所有垃圾回收器,有助于你理解不同垃圾回收器之间的差异。
GC标志(GC Flags)
最后,GC专用标志(flags)可以帮助你了解垃圾回收器可调节的属性,并检查其实际值。
“来源(Origin)”列显示了该标志的设置方式。“默认(Default)”值表示未从标准设置修改;“自适应(Ergonomic)”标志则由垃圾回收器自动调整。 如果你在命令行上设置了特定的GC标志,其来源会显示为“命令行(Command line)”。



















