type
Post
status
Published
date
Oct 27, 2026
slug
GC
summary
tags
技术探索
category
手写
icon
password

Go 的 GC 主要采用并发三色标记清扫机制。
首先,GC 会从 Goroutine 栈、全局变量等 GC Roots 出发,追踪所有可达对象。标记过程中,将对象逻辑上分成白色、灰色和黑色三种状态。灰色表示已经发现但还没有扫描完成的对象,黑色表示已经扫描完成的对象。等到所有灰色对象处理完毕,剩下的白色对象就是可以回收的垃圾。
为了减少业务暂停,Go 的大部分标记和清扫工作都可以与业务 Goroutine 并发执行。在 GC 准备和标记终止等阶段仍然有短暂 STW。第一次 STW 是为了安全地开始标记,第二次 STW 是为了安全地结束标记。
由于并发标记期间业务代码可能修改指针,Go 通过混合写屏障保证标记过程不会遗漏仍然存活的对象。
GC 的触发频率主要受堆增长、GOGC 和内存限制等因素影响。
什么是写屏障?
写屏障就是防止 GC 在并发标记时,因为指针关系发生变化而漏标存活对象。
举个例子:
假设有两个对象 A 和 B。
- A 是黑色:GC 已经扫描完 A。
- B 是白色:GC 还没有发现 B。
此时业务代码执行:
如果没有适当的保护机制,GC 可能不会重新扫描 A,也就可能漏掉 B。
最终 B 仍然是白色,被错误地当成垃圾回收,但实际上 A 正在引用它。
当业务代码修改指针时,写屏障会执行额外的标记操作,保护可能被遗漏的对象。
例如,在需要的情况下把 B 纳入 GC 的待标记对象集合。
这样,即使 A 已经扫描完成,GC 也不会漏掉仍然可达的 B。
三色标记具体怎么做?
- 从根引用找到对象,将它们放入灰色待扫描队列。
- 取出一个灰色对象,扫描它引用的其他对象。
- 将新发现的白色对象加入灰色队列。
- 当前对象扫描完成后变为黑色。
- 不断重复,直到没有灰色对象。
- 剩余的白色对象就是可回收对象。
第二次STW干了啥?
- 暂停业务 Goroutine,防止标记结束时继续产生新的并发变化。
- 确认所有标记任务完成,没有遗漏的待扫描对象。
- 关闭写屏障,结束标记阶段,进入后续清扫阶段。
分享
