Go的GC详细学习
Go语言的GC
三色标记法
- 所有初始对象都是白色的
- 从根对象开始扫描,所有可达对象为灰色,放入待处理集合
- 从待处理集合中取出灰色对象,将灰色对象的引用对象标记为灰色,自身为白色
- 重复第三步,直到没有灰色对象,就GC回收白色对象
STW全局暂停,还需要吗?
还需要,如果在GC期间,一个白色对象被黑色对象引用,那么这个白色对象是有用的,但是会被回收
写屏障技术
- 会拦截写操作
- 拦截完后,分别记录更新前后的新旧值,存储在一个队列里
- 如果队列慢了,就批量写到扫描队列里
go语言里的屏障技术
- 插入写屏障,当下游引用变更的时候,引用对象强制置灰
插入写需要STW,因为插入写只在堆上,所以堆上处理完后需要再STW后对栈扫描一次 - 删除写屏障,下游对象被删除或者被更换,那么被删除或者被更换的对象标记为灰色
删除写需要开始扫描的时候STW,保证所有堆对象处于灰色保护 - 混合写屏障
- 插入写屏障:
A → B(新指向)→ 标记 B 灰 - 删除写屏障:
A 原本 → C,现在去掉 → 标记 C 灰 - 混合写屏障: A 原本 → C,改成 → B
→ 标记 C 灰
→ 标记 B 灰
- 插入写屏障:
类型 | 特点 | Go 默认 |
---|---|---|
插入写屏障 | 只关心新值 | Go 1.8 之前 |
删除写屏障 | 只关心旧值 | 很少用 |
混合写屏障 | 同时关心旧值和新值,保证三色不变式 | Go 1.9+ |
阶段 | 是否 STW | 是否用写屏障 | 说明 |
---|---|---|---|
STW root 标记 | ✅ | ❌ | 暂停,扫描 root |
并发标记 | ❌ | ✅ | 用户程序继续跑,写屏障生效 |
并发清扫 | ❌ | ❌ | 不需要写屏障 |
STW 结束确认 | ✅ | ❌ | 停止所有,确认无漏扫,收尾 |
触发时机
- 手动触发:通过runtime.GC()来触发GC
- 被动触发:
- 后台两分钟没有产生GC,就强制触发
- 使用步调算法,如果内存分配到达阈值,就触发GC;可以通过debug.SetGCPercent(500)来修改上限
Go的GC详细学习
http://example.com/2024/01/07/Go的GC详细学习/