Go的GC详细学习

Go语言的GC

三色标记法

  1. 所有初始对象都是白色的
  2. 从根对象开始扫描,所有可达对象为灰色,放入待处理集合
  3. 从待处理集合中取出灰色对象,将灰色对象的引用对象标记为灰色,自身为白色
  4. 重复第三步,直到没有灰色对象,就GC回收白色对象

STW全局暂停,还需要吗?

还需要,如果在GC期间,一个白色对象被黑色对象引用,那么这个白色对象是有用的,但是会被回收

写屏障技术

  1. 会拦截写操作
  2. 拦截完后,分别记录更新前后的新旧值,存储在一个队列里
  3. 如果队列慢了,就批量写到扫描队列里

go语言里的屏障技术

  1. 插入写屏障,当下游引用变更的时候,引用对象强制置灰
    插入写需要STW,因为插入写只在堆上,所以堆上处理完后需要再STW后对栈扫描一次
  2. 删除写屏障,下游对象被删除或者被更换,那么被删除或者被更换的对象标记为灰色
    删除写需要开始扫描的时候STW,保证所有堆对象处于灰色保护
  3. 混合写屏障
    • 插入写屏障
      A → B(新指向)→ 标记 B 灰
    • 删除写屏障
      A 原本 → C,现在去掉 → 标记 C 灰
    • 混合写屏障: A 原本 → C,改成 → B
      → 标记 C 灰
      → 标记 B 灰
类型 特点 Go 默认
插入写屏障 只关心新值 Go 1.8 之前
删除写屏障 只关心旧值 很少用
混合写屏障 同时关心旧值和新值,保证三色不变式 Go 1.9+
阶段 是否 STW 是否用写屏障 说明
STW root 标记 暂停,扫描 root
并发标记 用户程序继续跑,写屏障生效
并发清扫 不需要写屏障
STW 结束确认 停止所有,确认无漏扫,收尾

触发时机

  1. 手动触发:通过runtime.GC()来触发GC
  2. 被动触发:
    1. 后台两分钟没有产生GC,就强制触发
    2. 使用步调算法,如果内存分配到达阈值,就触发GC;可以通过debug.SetGCPercent(500)来修改上限

Go的GC详细学习
http://example.com/2024/01/07/Go的GC详细学习/
作者
WoodQ
发布于
2024年1月7日
许可协议