当前位置: 首页 > news >正文

垃圾收集器ParNewCMS与底层三色标记算法详解

垃圾收集技术详解笔记

1. 分代收集理论

当前虚拟机的垃圾收集采用分代收集算法,根据对象存活周期将内存分为不同代区,以优化回收效率。

  • 核心分区
    • 新生代(Young Generation):对象存活周期短,约99%对象在每次回收时死亡。
    • 老年代(Old Generation):对象存活率高,无额外分配担保空间。
  • 算法选择
    • 新生代:适用复制算法(效率高,只需复制少量存活对象)。
    • 老年代:适用标记-清除或标记-整理算法(避免复制开销,但速度慢10倍以上)。
2. 垃圾收集算法详解
2.1 标记-复制算法

解决效率问题,将内存分为大小相等的两块。

  • 工作流程
    1. 使用其中一块内存。
    2. 当内存耗尽,将存活对象复制到另一块。
    3. 清理原内存块。
  • 内存变化示例
    • 整理前:碎片化状态。
    • 整理后:存活对象集中到另一块,内存连续。
  • 内存区域类型
    • 可用内存、可回收内存、存活对象、保留内存。
2.2 标记-清除算法

最基础算法,分“标记”和“清除”两阶段。

  • 工作流程
    • 标记存活对象(或需回收对象)。
    • 清除未标记对象。
  • 缺点
    • 效率问题:标记大量对象时性能低。
    • 空间问题:产生内存碎片(不连续空间)。
  • 内存变化示例
    • 整理前:碎片化状态。
    • 整理后:碎片化更严重,仅区分可用内存、可回收内存、存活对象。
2.3 标记-整理算法

专为老年代设计,标记后移动对象以消除碎片。

  • 工作流程
    1. 标记存活对象。
    2. 将所有存活对象向一端移动。
    3. 清理边界外内存。
  • 内存变化示例
    • 回收前:碎片化状态。
    • 回收后:对象紧凑排列,区分存活对象、可回收内存、未使用内存。
3. 垃圾收集器实现

收集器是算法的具体实现,需根据场景选择。无“万能”收集器。

3.1 Serial收集器(-XX:+UseSerialGC, -XX:+UseSerialOldGC)
  • 特点
    • 单线程收集器,工作时暂停所有线程(Stop The World)。
    • 简单高效(无线程交互开销)。
  • 算法
    • 新生代:复制算法。
    • 老年代:标记-整理算法。
  • 适用场景:客户端模式或小内存应用。
3.2 Parallel Scavenge收集器(-XX:+UseParallelGC, -XX:+UseParallelOldGC)
  • 特点
    • Serial的多线程版本(默认线程数 = CPU核数)。
    • 关注吞吐量(CPU运行用户代码时间占比)。
  • 算法
    • 新生代:复制算法。
    • 老年代:标记-整理算法。
  • Parallel Old收集器
    • Parallel Scavenge的老年代版本,多线程 + 标记-整理算法。
    • JDK8默认收集器,适合高吞吐场景。
3.3 ParNew收集器(-XX:+UseParNewGC)
  • 特点
    • 类似Parallel,但专为与CMS收集器配合设计。
    • 新生代使用复制算法。
  • 适用场景:Server模式下的首选(与CMS兼容)。
3.4 CMS收集器(-XX:+UseConcMarkSweepGC)
  • 特点
    • 并发收集器(最短停顿时间),用户线程与GC线程并行。
    • 基于标记-清除算法。
  • 工作流程
    1. 初始标记(STW):标记GC Roots直接引用对象。
    2. 并发标记:遍历对象图(无停顿)。
    3. 重新标记(STW):修正并发标记变动(用增量更新算法)。
    4. 并发清理:清除未标记对象。
    5. 并发重置:重置标记数据。
  • 缺点
    • CPU敏感(与业务线程抢资源)。
    • 浮动垃圾(并发阶段新垃圾需下次回收)。
    • 内存碎片(需定期整理)。
    • 不确定性(可能触发Concurrent Mode Failure,降级为Serial Old)。
  • 关键参数
    -XX:+UseConcMarkSweepGC     # 启用CMS  
    -XX:ConcGCThreads            # 并发GC线程数  
    -XX:+UseCMSCompactAtFullCollection  # FullGC后整理碎片  
    -XX:CMSFullGCsBeforeCompaction       # 多少次FullGC后整理一次(默认0)  
    -XX:CMSInitiatingOccupancyFraction   # 老年代使用比例触发FullGC(默认92%)  
    -XX:+CMSScavengeBeforeRemark         # CMS前启动Minor GC  
    
4. 亿级流量电商系统JVM优化案例

针对订单系统(8G内存,分配4G给JVM)。

  • 优化目标:减少Full GC(避免对象过早进入老年代)。
  • 参数配置
    -Xms3072M -Xmx3072M -Xmn2048M   # 堆大小(新生代2G)  
    -Xss1M                          # 线程栈大小  
    -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M  # 元空间  
    -XX:SurvivorRatio=8             # Eden与Survivor比例  
    -XX:MaxTenuringThreshold=5      # 对象年龄阈值(从15改为5)  
    -XX:PretenureSizeThreshold=1M   # 直接进入老年代对象大小阈值  
    -XX:+UseParNewGC -XX:+UseConcMarkSweepGC  # 新生代ParNew + 老年代CMS  
    -XX:CMSInitiatingOccupancyFraction=92     # 老年代92%触发FullGC  
    -XX:+UseCMSCompactAtFullCollection        # FullGC后整理碎片  
    -XX:CMSFullGCsBeforeCompaction=3          # 每3次FullGC整理一次  
    
  • 优化原理
    • 增大新生代(-Xmn2048M),减少对象动态年龄判断导致的过早晋升。
    • 降低对象年龄阈值(-XX:MaxTenuringThreshold=5),确保短期对象在Minor GC回收。
    • CMS默认参数适合高峰后Full GC(几小时一次)。
5. 垃圾收集底层算法
5.1 三色标记算法

解决并发标记中的漏标问题,将对象分为三色:

  • 黑色:已扫描完(安全存活)。
  • 灰色:已扫描,但引用未全扫描。
  • 白色:未扫描(不可达对象)。
  • 问题与解决
    • 多标(浮动垃圾):并发阶段局部变量销毁导致本应回收的对象未被回收(下一轮GC处理)。
    • 漏标:通过读写屏障解决:
      • 增量更新(CMS使用):黑色对象插入新引用时记录,重新扫描。
      • 原始快照(SATB, G1使用):灰色对象删除引用时记录,重新扫描。
  • 读写屏障实现
    // 写屏障示例(增量更新)  
    void oop_field_store(oop* field, oop new_value) {pre_write_barrier(field);    // 写前操作(记录旧值)*field = new_value;post_write_barrier(field, new_value); // 写后操作(记录新值)
    }
    
5.2 记忆集与卡表

解决跨代引用问题(如新生代引用老年代)。

  • 记忆集(Remember Set):记录跨代指针集合。
  • 卡表实现:字节数组(CARD_TABLE[]),每卡页512字节。
    • 卡页变脏(=1):有跨代指针时更新。
  • 维护:通过写屏障自动更新卡表状态。
6. 总结
  • 分代收集是JVM垃圾回收核心,新生代和老年代需匹配不同算法。
  • 收集器选择需权衡吞吐量(Parallel Scavenge)和停顿时间(CMS)。
  • 优化案例显示:合理配置新生代大小、对象年龄阈值及CMS参数可显著减少Full GC。
  • 底层算法(三色标记、读写屏障)确保并发标记的正确性,避免漏标。

http://www.lryc.cn/news/607747.html

相关文章:

  • 【云计算】云主机的亲和性策略(四):云主机组
  • VAST视频广告技术实现:从零开始搭建视频广告投放系统
  • 【20min 急速入门】使用Demucs进行音轨分离
  • 【云计算】云主机的亲和性策略(三):云主机 宿主机
  • 【Android】RecyclerView实现新闻列表布局(1)适配器使用相关问题
  • MySQL 运算符
  • 【Android】使用 Intent 传递对象的两种序列化方式
  • 【Android】进度条ProgressBar 可拖拽进度条Seekbar
  • Javaweb————Apache Tomcat服务器介绍及Windows,Linux,MAC三种系统搭建Apache Tomcat
  • Vue 详情模块 4
  • 分布式微服务--Nacos作为配置中心(二)
  • Text2SQL:如何通过自然语言直接获取数据,打破技术壁垒?
  • opencv自定义滤波
  • 入门MicroPython+ESP32:开启科技新旅程
  • 云原生三剑客:Kubernetes + Docker + Spring Cloud 实战指南与深度整合
  • Diffusion模型生产化指南:用LoRA技术快速定制企业专属AI画师
  • 电商API接口的优势、数据采集方法及功能说明
  • AIDL当Parcelable序列化的数据类通信时报“Class not found when unmarshalling“找不到该类时的解决方案
  • 存储成本深度优化:冷热分层与生命周期管理——从视频平台年省200万实践解析智能存储架构
  • Linux网络编程【UDP网络通信demon】
  • 编程与数学 03-002 计算机网络 19_网络新技术研究
  • 【DeepSeek-R1 】分词系统架构解析
  • fastGEO v1.7.0 大更新,支持PCA、差异分析、火山图、热图、差异箱线图、去批次等分析
  • 【05】VisionMaster入门到精通——圆查找
  • Spring Boot 全 YAML 配置 Liquibase 教程
  • 决策树算法:三大核心流程解析
  • 嵌入式系统的中断控制器(NVIC)
  • SpringCloud实战:机器人对战系统架构
  • 《软件测试与质量控制》实验报告二 单元测试
  • Terraria 服务端部署(Docker)