0

0

监控 JVM Full GC 次数的正确实践:避免 CMS 垃圾收集器计数误判

霞舞

霞舞

发布时间:2025-12-27 16:29:11

|

530人浏览过

|

来源于php中文网

原创

监控 JVM Full GC 次数的正确实践:避免 CMS 垃圾收集器计数误判

本文详解为何 `managementfactory.getgarbagecollectormxbeans()` 在 cms 垃圾收集器下会将一次 `jmap -histo:live` 触发的 full gc 误报为多次,揭示 cms 的 foreground 模式中 initial mark、remark 和 sweep 阶段均独立增加 `collectioncount` 的机制,并提供健壮、跨 gc 算法的监控方案。

在使用 ManagementFactory.getGarbageCollectorMXBeans() 监控 Full GC 次数时,你观察到:执行一次 jmap -histo:live(触发 Heap Inspection Initiated GC)后,日志显示仅发生一次 CMS Full GC,但程序却报告 add FullGC count:2 —— 这并非代码逻辑错误,而是 CMS 垃圾收集器在 foreground 模式下的固有行为

? 根本原因:CMS 的 “伪 Full GC” 阶段拆分

当 jmap -histo:live 触发 GC 时,JVM 会强制进入 CMS 的 foreground 模式(即暂停所有应用线程的同步回收),该模式并非单次原子操作,而是由多个可独立计数的子阶段组成:

  • Initial Mark(初始标记)→ collectionCount++
  • Remark(重新标记)→ collectionCount++
  • Sweep(清除)→ collectionCount++

查看你的 GC 日志可验证这一点:

# 第一次 jmap:包含 Remark + Sweep(共 2 次计数增量)
[Full GC (Heap Inspection Initiated GC) ... [CMS: ...] ... [weak refs processing] ... [class unloading] ... [scrub symbol/string table] ... ]
→ 实际触发了 Remark(含 class unloading/scrub)和 Sweep 两个独立阶段

# 第二次 jmap:仅 Sweep(1 次增量)
[Full GC (Heap Inspection Initiated GC) ... [CMS: 83931K->85173K(...) ...]

因此,bean.getCollectionCount() 返回的是 CMS 子阶段总执行次数,而非用户语义上的“一次完整的 Full GC”。这就是你看到 sum of fullgc:1, add FullGC count:2 的真实原因。

Lessie AI
Lessie AI

一款定位为「People Search AI Agent」的AI搜索智能体

下载

✅ 正确做法:区分 GC 类型 + 聚合统计

不应依赖单一 GarbageCollectorMXBean 的 getCollectionCount() 判断 Full GC,而应:

  1. 识别真正的 Full GC 收集器:CMS 的 ConcurrentMarkSweep 是并发收集器,其 getCollectionCount() 包含并发与 foreground 混合计数;真正执行 Full GC 的是 ParNew(年轻代)+ CMS(老年代)组合,但更可靠的方式是监听 GarbageCollectionNotification。

  2. 使用 JMX 通知机制(推荐)
    它能精确捕获每次 GC 的类型(endOfMajorGC / endOfMinorGC)、持续时间与内存变化,且不受 GC 算法内部阶段拆分影响:

import com.sun.management.GarbageCollectionNotificationInfo;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
import java.util.List;

public class GCMonitor {
    private static long fullGCCount = 0;

    public static void startMonitoring() throws Exception {
        List beans = ManagementFactory.getGarbageCollectorMXBeans();
        for (GarbageCollectorMXBean bean : beans) {
            ObjectName objName = ManagementFactory.newPlatformMXBeanObjectName(
                ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + "," +
                "name=" + ObjectName.quote(bean.getName())
            );
            ManagementFactory.getPlatformMBeanServer().addNotificationListener(
                objName,
                (notification, handback) -> {
                    if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {
                        GarbageCollectionNotificationInfo info =
                            GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData());
                        // 关键判断:Major GC(即 Full GC)通常作用于老年代(如 CMS Old Gen、G1 Old Generation)
                        if (info.getGcCause().contains("System.gc") ||
                            info.getGcCause().contains("Heap Inspection") ||
                            info.getGcName().toLowerCase().contains("old")) {
                            fullGCCount++;
                            System.out.printf("✅ Detected Full GC #%d: %s (%s) → %dms%n",
                                fullGCCount, info.getGcName(), info.getGcCause(), info.getGcInfo().getDuration());
                        }
                    }
                },
                null, null
            );
        }
    }
}
  1. 兼容性提醒(重要!)
    • CMS 已在 JDK 9 中被标记为 deprecated,JDK 14 起彻底移除。现代应用应迁移到 G1 或 ZGC。
    • G1/ZGC 的 getCollectionCount() 行为更符合直觉:一次 jmap -histo:live 仅触发 1 次 collectionCount 增量(对应一次 Mixed GC 或 Full GC)。
    • 若必须支持旧版 CMS,请始终以 GarbageCollectionNotification 为准,放弃轮询 getCollectionCount()。

? 总结

  • ❌ 错误认知:getCollectionCount() = Full GC 次数(尤其在 CMS foreground 模式下不成立)
  • ✅ 正确认知:它是 GC 子阶段执行总次数,CMS 下一次 jmap 可能触发多次计数
  • ✅ 最佳实践:使用 GarbageCollectionNotification 监听,结合 gcCause(如 "Heap Inspection")和 gcName(如 "CMS Old Gen")精准识别 Full GC
  • ⚠️ 长期建议:升级至 G1/ZGC,简化监控逻辑并获得更好性能与可观测性

通过以上改进,你的 Full GC 监控将真正反映 JVM 行为本质,而非 GC 算法的实现细节陷阱。

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

197

2023.11.20

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

480

2023.08.10

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

402

2023.08.14

Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

公务员递补名单公布时间 公务员递补要求
公务员递补名单公布时间 公务员递补要求

公务员递补名单公布时间不固定,通常在面试前,由招录单位(如国家知识产权局、海关等)发布,依据是原入围考生放弃资格,会按笔试成绩从高到低递补,递补考生需按公告要求限时确认并提交材料,及时参加面试/体检等后续环节。要求核心是按招录单位公告及时响应、提交材料(确认书、资格复审材料)并准时参加面试。

37

2026.01.15

公务员调剂条件 2026调剂公告时间
公务员调剂条件 2026调剂公告时间

(一)符合拟调剂职位所要求的资格条件。 (二)公共科目笔试成绩同时达到拟调剂职位和原报考职位的合格分数线,且考试类别相同。 拟调剂职位设置了专业科目笔试条件的,专业科目笔试成绩还须同时达到合格分数线,且考试类别相同。 (三)未进入原报考职位面试人员名单。

52

2026.01.15

国考成绩查询入口 国考分数公布时间2026
国考成绩查询入口 国考分数公布时间2026

笔试成绩查询入口已开通,考生可登录国家公务员局中央机关及其直属机构2026年度考试录用公务员专题网站http://bm.scs.gov.cn/pp/gkweb/core/web/ui/business/examResult/written_result.html,查询笔试成绩和合格分数线,点击“笔试成绩查询”按钮,凭借身份证及准考证进行查询。

8

2026.01.15

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

65

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

36

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.5万人学习

C# 教程
C# 教程

共94课时 | 6.8万人学习

Java 教程
Java 教程

共578课时 | 46.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号