Java中通过GarbageCollectorMXBean可获取GC累计次数和总耗时,但需自行差值计算频率与平均单次耗时;须按名称区分Young GC和Full GC并独立监控,结合NotificationListener捕获单次详情。

Java 中通过 GarbageCollectorMXBean 可以直接获取各垃圾收集器的累计回收次数和总耗时,但要注意:这些是**自 JVM 启动以来的累加值**,不是实时频率或单次耗时。要得到“回收频率”(如每分钟多少次)和“平均单次耗时”,必须自行做差值计算与时间窗口统计。
获取基础统计值(名称、次数、总耗时)
每个 GarbageCollectorMXBean 实例对应一个 GC 算子(例如 PS Scavenge 对应 Young GC,PS MarkSweep 或 G1 Old Generation 对应 Full GC)。调用以下方法即可拿到原始数据:
-
名称:
gcBean.getName()—— 区分年轻代/老年代收集器 -
累计次数:
gcBean.getCollectionCount()—— 若返回 -1 表示该指标不可用(如某些 GC 算子未启用) -
累计耗时(毫秒):
gcBean.getCollectionTime()—— 同样可能为 -1
计算回收频率(单位时间内的次数)
频率不能靠单次读取得出,需定时采样并计算差值。例如每 10 秒采集一次,再换算成每分钟次数:
- 记录上一次的
countLast和采集时间timeLast - 本次读取
countNow和当前系统时间timeNow - 频率 ≈
(countNow - countLast) / (timeNow - timeLast) × 60(次/分钟) - 建议使用
ScheduledExecutorService固定周期执行,避免阻塞主线程
推导平均单次耗时与异常暂停
总耗时除以总次数可得历史平均值,但更关键的是识别长暂停事件:
- 平均单次耗时 =
collectionTime / Math.max(1, collectionCount) - 单次 GC 耗时无法直接获得,需结合 GC 事件监听(注册
NotificationListener监听"GC_NOTIFICATION")才能捕获每次触发的精确开始时间、持续时间和内存变化 - 若某次
duration > 1000(即超 1 秒),就属于高风险暂停,应立即告警
区分 Young GC 和 Full GC 进行独立监控
多数 JVM 默认暴露至少两个收集器 Bean,顺序通常为:第一个是年轻代,第二个是老年代(但不绝对,需按名称判断):
- 检查
name.contains("Young") || name.contains("Scavenge") || name.contains("ParNew") || name.contains("G1 Young")—— 判定为 Young GC - 检查
name.contains("Old") || name.contains("MarkSweep") || name.contains("G1 Old") || name.contains("ConcurrentMarkSweep")—— 判定为 Full GC - 分别维护两组计数器与时间戳,避免把 Young GC 频繁但轻量的行为和 Full GC 罕见但沉重的行为混为一谈










