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

Go(三)GC垃圾回收

5、Golang三色标记混合写屏障GC模式全分析 · 语雀本节为重点章节本章节含视频版:视频链接地址:https...https://www.yuque.com/aceld/golang/zhzanb

1. 核心痛点:STW (Stop The World)

在了解三色标记法之前,必须先了解 STW。 最原始的 GC(如 Go 1.0)在清理垃圾时,必须暂停整个程序所有的 Goroutine,不准任何人修改内存,然后慢慢扫描、清理,最后再恢复程序运行。这个全局暂停的时间就是 STW。如果内存很大,STW 会长达几百毫秒甚至几秒,这对高并发 Web 服务和游戏服务器是致命的。

因此,Go GC 演进的终极目标只有一个:将 STW 时间压榨到极致(目前通常在 1 毫秒以内),让 GC 过程和用户的业务代码并发执行。

2. 核心算法:三色标记法 (Tri-color Marking)

为了实现并发扫描,Go 将内存里的所有对象在逻辑上分为三种“颜色”状态:

  • ⚪ 白色(White):潜在的垃圾。刚开始扫描时,所有对象都是白色的。如果扫描结束后还是白色,就会被当成垃圾回收掉。

  • 🔘 灰色(Grey):存活对象。表示该对象已经被 GC 扫描到了,但它引用的其他对象还没被扫描完。灰色相当于一个待处理的工作队列。

  • ⚫ 黑色(Black):绝对存活对象。表示该对象已经被扫描,并且它引用的所有子对象也都已经被扫描过了。黑色对象是安全的,绝不会被当成垃圾。

扫描工作流:
  1. 起步:将所有对象标记为白色。

  2. 找根(Root):从程序的根节点(如全局变量、当前运行 Goroutine 的栈变量)出发,找到它们直接引用的对象,把这些对象涂成灰色

  3. 顺藤摸瓜:从灰色对象集合中取出一个对象,把它涂成黑色。然后把它直接引用的所有白色子对象涂成灰色

  4. 循环往复:重复第 3 步,直到内存里没有任何灰色对象为止。

  5. 一键清空:此时,内存里只剩下黑色(存活的有用对象)和白色(没人要的孤儿对象)。直接把所有的白色对象清理掉(Sweep)。

3. 致命危机:并发标记的“丢包”问题

既然我们的目标是“并发”,也就是 GC 在扫描变颜色的同时,用户的 Goroutine 还在疯狂运行、修改引用关系。这就会导致一个致命 Bug:存活的对象被当成垃圾误杀了。

误杀必须同时满足两个条件:

  1. 一个黑色对象(已经扫描完不再回头看)突然指向了一个白色对象。

  2. 同时,那个白色对象原本唯一依赖的灰色父节点,把这段引用给删除了。

结果就是:黑色对象拉住了白色对象,但由于黑色对象不会被二次扫描,这个白色对象永远变不成灰色和黑色,最终在清除阶段被冤死。

4. 终极解法:混合写屏障 (Hybrid Write Barrier)

为了解决并发误杀,Go 在 1.8 版本引入了混合写屏障技术。 “屏障”就像是内存操作的一个“钩子(Hook)”。当用户代码试图修改对象的引用时,会自动触发一小段额外的逻辑。

混合写屏障的精髓在于它破坏了误杀条件:

  • 无论你把一个引用改成指向谁,或者删除了对谁的引用,只要涉及引用的变动,系统都会强制把相关的对象涂成灰色。

  • 这是一种“宁可错杀(留下一点本该清理的浮动垃圾留到下个周期),绝不放过(绝不误杀存活对象)”的保底策略。

借助混合写屏障,Go 的 GC 就可以放心地和用户代码并发运行,只需要在极短的时间内进行 STW(用于开启屏障和做最后的收尾确认),极大地提升了性能

http://www.cnnetsun.cn/news/2738632.html

相关文章:

  • 【2027最新】基于SpringBoot+Vue的社区医院管理系统管理系统源码+MyBatis+MySQL
  • LLVM IR指令避坑指南:那些容易让人误解的 `phi`、`getelementptr` 和 `poison value`
  • 淘宝账号自动续期工具:定时产出可用登录凭证供爬虫调用
  • 如何快速实现文本差异比对:JavaScript开发者的完整指南
  • 构建可观测性:如何监控、调试与追踪复杂的 Multi-Agent 系统
  • NBTExplorer完整教程:如何轻松编辑我的世界游戏数据
  • SPI协议核心知识点总结,面试必问!!
  • 从Word迁移到LaTeX避坑指南:我踩过的公式编号、图片路径和参考文献引用这些‘雷’
  • 别再只会Ctrl+N了!Simulink模型模板(.sltx)的保姆级创建与使用指南
  • 别再手动排版了!手把手教你用Overleaf套用BMC期刊LaTeX模板(附公式、图表、参考文献保姆级教程)
  • 从收音机到智能仪表:用STM32F103+HT1621驱动老式段码屏的实战改造指南
  • 新手小牛--TTL与非门超详细工作原理
  • STM32单片机,通过Flash模拟U盘运用FATFS管理文件
  • PanTools (多网盘批量管理工具) v1.1.18 中文绿色版
  • 深度解析:douyin-downloader 抖音批量下载工具的技术架构与实战应用
  • Windows系统自动化配置工具架构解析:实现原理与性能优化指南
  • SpaceX拟750亿美元募资上市,1.75万亿美元估值能否撑起商业帝国扩张?
  • 量子计算在数据质量管理与异常检测中的应用
  • 别再只会用Postman了!用HttpClient在Java里玩转微信登录(附工具类封装)
  • Windows 11系统瘦身秘籍:3步告别臃肿,让你的电脑重获新生
  • 设计走查表与设计还原度优化:像素级精准的工程实践
  • 把开发环境装进U盘:用WTG打造一个即插即用的Python/数据分析移动工作站
  • Axure RP中文界面3步搞定:告别英文困扰,轻松实现专业原型设计
  • 从PBMC数据实战出发:手把手教你用Scanpy完成细胞类型注释全流程(含Marker基因字典与聚类验证)
  • 如何用零代码数据采集工具破解闲鱼市场情报困局?
  • 除了KMS激活失败,Windows Server 2016自动关机还有这个隐藏原因和临时救急脚本
  • 从RC滤波到双稳态:分立元件声控逻辑电路设计与实践
  • Win11 WSL2 + Ubuntu 18.04:不止装ROS,打造你的机器人开发一体化环境(含CUDA/PyTorch配置)
  • Android平台上的统一SDR驱动架构:rtl_tcp_andro的技术实现与应用生态
  • 深入探讨 Go 语言中 context上下文控制 的底层实现与并发安全