Go(三)GC垃圾回收

发布时间:2026/6/4 1:49:12

Go(三)GC垃圾回收 5、Golang三色标记混合写屏障GC模式全分析 · 语雀本节为重点章节本章节含视频版:视频链接地址https...https://www.yuque.com/aceld/golang/zhzanb1. 核心痛点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绝对存活对象。表示该对象已经被扫描并且它引用的所有子对象也都已经被扫描过了。黑色对象是安全的绝不会被当成垃圾。扫描工作流起步将所有对象标记为白色。找根Root从程序的根节点如全局变量、当前运行 Goroutine 的栈变量出发找到它们直接引用的对象把这些对象涂成灰色。顺藤摸瓜从灰色对象集合中取出一个对象把它涂成黑色。然后把它直接引用的所有白色子对象涂成灰色。循环往复重复第 3 步直到内存里没有任何灰色对象为止。一键清空此时内存里只剩下黑色存活的有用对象和白色没人要的孤儿对象。直接把所有的白色对象清理掉Sweep。3. 致命危机并发标记的“丢包”问题既然我们的目标是“并发”也就是 GC 在扫描变颜色的同时用户的 Goroutine 还在疯狂运行、修改引用关系。这就会导致一个致命 Bug存活的对象被当成垃圾误杀了。误杀必须同时满足两个条件一个黑色对象已经扫描完不再回头看突然指向了一个白色对象。同时那个白色对象原本唯一依赖的灰色父节点把这段引用给删除了。结果就是黑色对象拉住了白色对象但由于黑色对象不会被二次扫描这个白色对象永远变不成灰色和黑色最终在清除阶段被冤死。4. 终极解法混合写屏障 (Hybrid Write Barrier)为了解决并发误杀Go 在 1.8 版本引入了混合写屏障技术。 “屏障”就像是内存操作的一个“钩子Hook”。当用户代码试图修改对象的引用时会自动触发一小段额外的逻辑。混合写屏障的精髓在于它破坏了误杀条件无论你把一个引用改成指向谁或者删除了对谁的引用只要涉及引用的变动系统都会强制把相关的对象涂成灰色。这是一种“宁可错杀留下一点本该清理的浮动垃圾留到下个周期绝不放过绝不误杀存活对象”的保底策略。借助混合写屏障Go 的 GC 就可以放心地和用户代码并发运行只需要在极短的时间内进行 STW用于开启屏障和做最后的收尾确认极大地提升了性能

相关新闻