【Golang】GC垃圾回收机制

  • ~1.73K 字
  1. 1. 标记清除法
    1. 1.1. 流程
    2. 1.2. 缺点
  2. 2. 三色标记法
    1. 2.1. 流程
    2. 2.2. 无STW
    3. 2.3. 强弱三色不变式
  3. 3. 屏障
    1. 3.1. 插入屏障
    2. 3.2. 删除屏障
    3. 3.3. 混合写屏障
      1. 3.3.1. 场景1
      2. 3.3.2. 场景2
      3. 3.3.3. 场景3
      4. 3.3.4. 场景4

参考视频:Golang中GC回收机制三色标记与混合写屏障

标记清除法

该方法是golang v1.3的垃圾回收机制

流程

假设一个程序和对象的可达关系如下:

则具体回收机制如下:

  • 首先执行STW(Stop the World)
  • 遍历所有对象并将全部可达对象标记(图中为1 2 3 4 7)
  • 没有被标记的即为垃圾,会被回收
  • 结束STW

缺点

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

早期有尝试过将STW和清除交换顺序,使STW窗口变小,但是用处不大

三色标记法

流程

三色标记法会统计三个集合:白色、灰色和黑色

程序创建时,将所有节点标记为白色,放入白色集合

将程序展开为根集合,以根集合中的节点为起点,遍历根集合(非递归),得到灰色节点,并移入灰色集合

接下来遍历灰色集合,将可达对象从白色标记为灰色,遍历后的灰色标记为黑色,移入黑色集合

重复上一步,直到灰色集合中没有任何对象,此时剩余的白色对象就是垃圾,收集所有白色对象

无STW

若没有STW:一开始对象2的指针指向对象3,在还没扫描到对象2的时候,已被标记为黑色的对象4创建了指向对象3的指针,与此同时对象2移除指向对象3的指针,此时对象3就挂在了已经扫描完成的黑色对象4下

按照正常逻辑,对象2 3标记为黑色,而对象3无法被遍历到,会被认为是垃圾,等待回收清除

综上,在不STW的情况下,如果同时满足如下两个条件,就会出现对象丢失的现象:

  • 一个白色对象被黑色对象引用
  • 灰色对象和它之间的可达关系的白色对象遭到破坏

强弱三色不变式

通过两种三色不变式来破坏上面的两种条件

强三色不变式:强制性的不允许黑色对象引用白色对象

弱三色不变式:白色对象存在其他灰色对象对他的引用,或者可达它的链路上游存在灰色对象时,黑色对象可以引用白色对象

在三色标记中如果满足强/弱三色不变式之一,即可保证对象不丢失

屏障

屏障提供了一种额外的判断机制,不打扰正常程序运行

插入屏障

在A对象引用B对象时,B对象被标记为灰色(即将B挂在A下游时,B必须被标记为灰色),它满足强三色不变式

注意:插入屏障不在栈上执行,为了不拖累栈的效率

为了防止漏扫,在回收白色之前,加STW重新扫描一次栈空间,进行一次三色标记

插入写屏障因为要加一次STW,所以会慢10-100ms

删除屏障

被删除的对象如果自身为灰色或者白色,则标记为灰色,它满足弱三色不等式

假如这里对象1要删除对象5,对象5是白色的,则自身被标记为灰色

它的不足之处在于回收精度低:一个对象即使被删除了最后一个指向它的指针也可以活过这一轮,在下一轮GC被清理掉

混合写屏障

操作如下:

  • GC开始时将栈上的对象全部扫描并标记为黑色
  • GC期间,任何在栈上创建的新对象,均为黑色
  • 被删除、添加的对象标记为灰色

它满足变形的弱三色表达式

注意·:为了保证效率,栈不启用屏障

GC开始时,默认为白色,优先扫描栈,把栈中的可达对象全部标记为黑色

场景1

对象被一个堆对象删除引用,成为栈对象的下游

如:对象7添加到对象1的下游,对象4删除对象7的引用,此时对象4处于堆区,会触发写屏障,标记对象7为灰色

场景2

对象被一个栈对象删除引用,称为另一个栈对象的下游

如:我们新建一个对象9在栈上,此时会被标记为黑色,对象9添加下游对象3,然后对象2删除对象3的引用关系

若没有new对象9,直接删除2和3的关系,则会触发弱三色不变式,延迟一轮删除对象3

场景3

对象被一个堆对象删除引用,成为另一个堆对象的下游

如:堆对象10已经被扫描为黑,它添加下游引用堆对象7,触发屏障机制,标记为灰色

场景4

对象从一个栈对象删除引用,成为另一个堆对象的下游

如:接下来栈对象1要删除栈对象2的引用,堆对象4删除引用对象7的关系,转移到对象2,此时触发写屏障,对象7被标记为灰色

赞助喵
非常感谢您的喜欢!
赞助喵