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

GC全场景分析

GC全场景分析

文章目录

  • GC全场景分析
    • 标记-清除法
      • **标记 - 清除法核心流程与 STW 机制**
      • **标记 - 清除法四步流程**
        • **1. STW 启动(暂停用户线程)**
        • **2. 标记可达对象(从根集合出发)**
        • **3. 清除未标记对象(回收堆内存)**
        • **4. 恢复用户线程(结束 STW)**
      • **根集合(Root Set)深度解析**
        • **1. 本质与作用**
        • **2. 分布与组成**
        • **3. 与 GC 的关键关系**
      • **对比与总结**
    • 三色标记法与屏障机制
        • **基本概念**
        • **标记流程**
    • 混合写屏障机制
        • **混合写屏障的核心规则**
        • **混合写屏障的 GC 流程改进**
        • **关键优势**
        • **与传统屏障的对比**
        • **示例说明**
      • **总结**

首先,GC 是一种垃圾处理机制。实现的方式由很多种算法:标记-清除法、三色标记法、屏障机制、混合写屏障机制等。下面,我将从go的角度,go实现过的gc算法进行学习记录和分析。

标记-清除法

标记 - 清除法核心流程与 STW 机制

核心动作:STW(Stop The World)

  • 定义:暂停所有应用程序线程,仅允许 GC 线程执行,确保垃圾回收过程中对象引用关系不变。
  • 目的
    ✅ 避免并发修改导致 浮动垃圾(应回收的对象未被标记)或 误标记(不可达对象被错误标记为存活)。
    ✅ 简化 GC 算法逻辑,无需处理多线程竞争问题。

标记 - 清除法四步流程

1. STW 启动(暂停用户线程)
  • 操作
    • GC 线程向所有应用线程发送暂停请求。
    • 线程执行到 安全点(Safepoint,如方法调用、循环结束处) 时主动暂停,确保此时对象引用稳定。
  • 关键点
    • 安全点机制避免线程在非稳定状态被暂停(如正在修改对象引用时)。
2. 标记可达对象(从根集合出发)
  • 标记逻辑
    • 根集合(Root Set) 开始,递归遍历所有 可达对象,标记为 存活(而非 “空闲”)。
    • 根集合组成
      ▶ 栈内存:线程栈中的局部变量、方法参数(对象引用)。
      ▶ 方法区:静态变量、类的 Class 对象。
      ▶ 寄存器:CPU 寄存器中存储的引用。
      ▶ JNI 引用:本地代码持有的全局对象引用。
  • 核心作用
    通过根集合确定所有存活对象,未被标记的对象判定为可回收垃圾。
3. 清除未标记对象(回收堆内存)
  • 操作
    扫描整个堆内存,释放所有未被标记的对象占用的空间。
  • 副作用
    ❗ 产生 内存碎片(不连续的空闲块),可能导致后续大对象分配失败,触发更多 GC。
4. 恢复用户线程(结束 STW)
  • 操作
    GC 完成后,通知所有应用线程从安全点继续执行。
  • 影响
    STW 期间应用无响应,过长的 STW 会导致系统延迟升高(如实时系统、高并发服务)。

根集合(Root Set)深度解析

1. 本质与作用
  • 定义:GC 标记的 初始起点集合,包含所有 直接可达的对象引用
  • 核心作用
    ✅ 作为递归遍历的起点,确保所有存活对象被标记。
    ✅ 隔离堆内存:GC 仅需关注根集合可达的对象,无需扫描整个堆。
2. 分布与组成
内存区域根集合成员示例
栈内存方法内的局部变量(如Object obj = new Object();
方法区静态变量(如static Object staticObj;)、类的 Class 对象
寄存器CPU 寄存器中存储的对象引用(由 JVM 底层管理)
JNI 本地堆本地代码通过NewGlobalRef创建的全局引用
3. 与 GC 的关键关系
  • 标记阶段的起点

    根集合 → 对象A → 对象B → 对象C(标记为存活)  
    ↘ 对象D(标记为存活)  
    

    未被根集合直接或间接引用的对象(如孤立对象)将被清除。

  • STW 的必要性
    若不暂停线程,根集合中的引用可能在标记过程中被修改(如赋值为null),导致标记结果错误。

对比与总结

维度标记 - 清除法根集合特点
STW 作用确保标记 / 清除阶段对象引用不变分布在栈、方法区、寄存器等多区域
标记对象存活对象(可达对象)包含静态变量、局部变量等直接引用
内存碎片会产生无需移动对象,仅标记 - 清除
优化方向结合分代 GC、增量标记减少 STW 时间减少静态变量引用,避免长生命周期对象

核心结论

  • 标记 - 清除法通过 STW 和根集合实现垃圾回收,适用于简单场景,但需注意内存碎片问题。
  • 根集合是 GC 的 “起点”,其组成与内存分布直接影响 GC 效率,合理管理根引用(如避免冗余静态变量)可优化 GC 性能。

三色标记法与屏障机制

基本概念
  • 三色定义
    • 白色:初始状态,未被垃圾回收器(GC)访问的对象
    • 灰色:已被 GC 访问,但内部引用的对象还未全部处理完
    • 黑色:已被 GC 完全处理,其引用的对象均已扫描完成
标记流程
  1. 初始标记(STW 阶段)
    • 暂停所有用户线程
    • 从根集合(全局变量、栈上变量等)出发,标记所有直接可达对象为灰色,并放入灰色队列
  2. 并发标记
    • 用户线程与 GC 线程同时运行
    • 处理灰色队列
      • 取出灰色对象,将其引用的白色对象标记为灰色并加入队列
      • 该灰色对象标记为黑色
    • 写屏障
      • 删除屏障:当灰色对象删除对白色对象的引用时,强制将白色对象标记为灰色
      • 插入屏障:黑色对象新增白色对象引用时,将白色对象标记为灰色
  3. 最终标记(STW 阶段)
    • 短暂暂停用户线程
    • 处理并发阶段遗留的少量标记任务,确保标记完整性
  4. 清除阶段
    • 回收所有白色对象(即不可达对象)
    • 重置黑色和灰色对象为白色,为下次 GC 做准备

混合写屏障机制

Go 语言从 1.8 版本开始引入混合写屏障,主要解决传统屏障的局限性:

  • 插入屏障(Insert Barrier):黑色对象插入白色对象引用时需标灰,但栈上对象扫描需 STW(因栈不适用写屏障)。
  • 删除屏障(Delete Barrier):灰色对象删除白色对象引用时需标灰,但可能导致浮动垃圾(本轮 GC 未回收)。

混合写屏障的目标

  1. 减少 STW 时间:避免扫描栈时的 STW。
  2. 简化 GC 流程:合并插入与删除屏障的优势。
混合写屏障的核心规则

混合写屏障同时应用以下两条规则:

  1. 插入屏障
    黑色对象引用白色对象时,强制将白色对象标记为灰色

    A().field = B() → B被标记为灰色
    
  2. 删除屏障(弱化版)
    对象(无论黑白)**删除对**白色对象的引用时,将该白色对象标记为灰色

    A(/).field = nil(原指向B()) → B被标记为灰色
    
  3. 栈保护
    栈上对象的引用变更不触发写屏障,但 GC 开始时会对栈进行并发扫描,扫描完成后栈上对象视为黑色(不再二次扫描)。

混合写屏障的 GC 流程改进
  1. 初始标记(STW)
    • 扫描根对象(全局变量、寄存器),标记直接可达对象为灰色。
    • 栈扫描:并发扫描所有 goroutine 的栈,标记栈上对象(但不扫描其引用的对象)。
  2. 并发标记
    • 处理灰色队列,标记对象为黑色。
    • 写屏障确保:
      ▶ 黑色对象新增白色引用时,白色对象被标灰。
      ▶ 对象删除白色引用时,白色对象被标灰。
    • 栈处理
      栈上对象在初始扫描后视为黑色,后续变更不触发屏障(依赖初始扫描的正确性)。
  3. 最终标记(STW)
    • 仅需短暂 STW,处理少量未完成的标记任务(如栈上残留的白色对象),无需重新扫描栈。
  4. 清除阶段
    • 并发清除所有白色对象。
关键优势
  1. 减少 STW 时间
    • 栈扫描与用户线程并发进行,仅需初始 STW 扫描一次,无需像插入屏障那样在标记结束后重新 STW 扫描栈。
  2. 简化 GC 流程
    • 统一处理堆上的插入和删除操作,逻辑更简洁。
  3. 降低内存压力
    • 相比删除屏障,混合写屏障减少了浮动垃圾的产生(因插入屏障的存在)。
与传统屏障的对比
特性插入屏障删除屏障混合写屏障
栈扫描 STW需要两次(初始 + 最终)仅初始一次仅初始一次(扫描一次栈全黑,使得无需二次扫描)
浮动垃圾有(下轮 GC 回收)极少(插入屏障抑制)
写屏障复杂度仅处理插入操作仅处理删除操作同时处理插入和删除
Go 版本1.5-1.7历史方案(未实际使用)1.8+
示例说明
// 场景:黑色对象A引用白色对象B,同时灰色对象C删除对B的引用
A.field = B  // 混合写屏障:B被标记为灰色(插入规则)
C.field = nil // 混合写屏障:B已被标灰(插入规则已处理),无需重复操作

通过混合写屏障,B 在被 A 引用时已被标灰,即使 C 删除引用,B 仍会被正确标记为存活对象。

总结

混合写屏障是 Go 语言 GC 的核心优化,通过合并插入与删除屏障的优势,大幅减少 STW 时间,同时降低内存压力。其核心设计思想是:

  1. 并发栈扫描:避免栈操作的写屏障,通过初始 STW 扫描一次栈。
  2. 堆上双重保护:通过插入和删除规则,确保引用变更时对象被正确标记。
  3. 最终 STW 优化:仅需短暂暂停处理残留任务,无需重新扫描栈。

这使得 Go 语言的 GC 在保证正确性的同时,实现了极致的低延迟,特别适合高并发场景。

相关文章:

  • Redis进阶知识
  • 服务端高并发分布式结构演进之路
  • 51单片机,两路倒计时,LCD1602 ,Proteus仿真
  • ubuntu的虚拟机上的网络图标没有了
  • Go语言中函数 vs 方法
  • STM32项目实战:ADC采集
  • Gartner《如何将生成式人工智能(GenAI)集成到应用架构》学习心得
  • elementplus menu 设置 activeindex
  • 探索用户行为数据分析——从基础查询到高级分析 【GaussDB(for MySQL)】
  • DeepSeek本地部署全攻略:从零搭建到Web可视化及数据训练
  • Java程序员学AI(一)
  • Linux(2)——shell原理及Linux中的权限
  • GLPK(GNU线性规划工具包)中建模语言MathProg的使用
  • MySQL 数据库备份与还原
  • Python训练营打卡 Day29
  • tomcat查看状态页及调优信息
  • 【数据结构】1-3 算法的时间复杂度
  • 掘金欧洲宠物经济新蓝海:比利时天然宠粮市场爆发与跨境新机遇
  • OpenSearch入门:从文档示例到查询实战
  • Linux `touch` 命令深度解析与高阶应用指南
  • 专访|金七猫奖得主:以非遗为舟,在现实题材中疗愈与成长
  • 著名文学评论家、原伊犁师范学院院长吴孝成逝世
  • 芬兰西南部两架直升机相撞坠毁,第一批救援队已抵达现场
  • 陶石不语,玉见文明:临平玉架山考古博物馆明日开馆
  • 泽连斯基:俄代表团级别低,没人能做决定
  • 美国将与阿联酋合作建立海外最大的人工智能数据中心