Go GC

Go1.5 标记删除(Mark and Sweep)

原理

  • 进入STW(Stop The World)阶段
  • 遍历整个heap,排查未被引用的对象,并标记;
  • 暂停STW
  • 执行Sweep清除

缺点

  • STW会让Go程序暂停,程序出现卡顿
  • 标记需要扫描整个heap
  • 清除数据会产生heap碎片

Go1.8 三色标记法 + 写入屏障

三色标记法

原理

  • 维护三个标记表:白色灰色黑色
  • 程序初始时,所有对象标记为白色
  • 从Root Set开发,每次只遍历一层,标记该层的对象为灰色(对象从白色表中移到灰色表)
  • 然后,以灰色标记表开始,遍历该表中的对象,将从这些对象开始的可达到对象(走一步),标记为灰色,同时灰色表中已经遍历过的对象,标记为黑色(对象从灰色表中移到黑色表)
  • 循环上一步,继续遍历灰色表,直到灰色表中无任何对象
  • 剩下的白色即为需要删除的对象

上述过程,仍然需要STW,否则会出现并发导致的引用关系错乱,导致资源被错误的GC删除

写入屏障

原理

  • 三色标记被破坏的情况有两种:

    1. 一个白色对象被黑色对象引用
    2. 灰色对象与它的可达白色对象关系遭到破坏(灰色同时丢失了该白色)
  • 谷歌提出了两个三色不变色:

    1. 强三色不变性:强制性不允许黑色引用白色
    2. 弱三色不变性:黑色可以引用白色,但白色对像存在其它灰色(可非直接上级节点)引用该白色对象
  • 只要三色不变色满足上述条件之一,即可解决三色标记必须使用STW问题

插入写屏障

插入屏障原理

  • 对堆对象,在对象被引用时触发,A引用B时,B对象标记为灰色
  • 对栈对象,对象被引用时,不触发该过程以避免该标记过程对程序性能的影响;
  • 此时在GC过程,遍历灰色表的过程,不需要STW,直到灰色表为空结束
  • 而此时栈上黑色对象可能引用白色对象,为解决这个问题,需要在上一步灰色表为空时,执行一些STW,并将栈上所有对象都标记为白色,并对这些对象重新执行一遍扫描;

缺点:在结束时,还需要额外扫描一次栈上的对象引用链,这会引入10-100ms;

删除屏障原理

  • 被删除对象,如果自身为灰色白色,则会被标记为灰色
  • 该过程是满足弱三色不变式,保证灰色对象到白色对象的路径不会断;

缺点:被删除对象,当前这一轮GC不会被删掉(因为会被转换成黑色),但会在下轮GC中删掉;

混合写屏障

原理

  • GC开始时,扫描栈上的可达对象全部标记为黑色(期间不需要STW)
  • GC期间,任何在栈上创建的新对象,均为黑色
  • 被删除对象,被标记为灰色
  • 被添加的对象标记为灰色

满足变形的弱三色不变色,混合了插入,删除写屏障的优点