本网站可以通过分类标签帮助你快速筛选出你想看的文章,记住地址:www.Facec.cc

golang GC垃圾回收原理

一、go语言中的GC

go语言GC机制经过多年的迭代最终性能良好。

一个概念:
STW:stop the word,指程序执行过程中,中断暂停程序逻辑,专门去进行垃圾回收。

二、标记清除法

把根数据段上的数据作为root,基于他们进行进一步的追踪,追踪到的数据就进行标记,最后把没有标记的对象当作垃圾进行释放。

  1. 开启STW,
  2. 从根节点出发,标记所有可达对象
  3. 停止STW,然后回收所有未标记的对象。

三、三色标记法

用 白灰黑三色

  1. 初始时,所有对象都为白色
  2. GC开始,开启SWT,遍历堆栈root,将直接可达的对象标记为灰色
  3. 遍历灰色结点,将直接可达的对象标记为灰色,自身标记为黑色
  4. 继续执行第三步同样的步骤,直到所有能够访问到的结点都被标记为黑色
  5. 关闭SWT,回收所有白色标记的对象。

注意: 如果没有SWT,程序正常执行,可能会有如下的情况,导致对象被误当作垃圾回收。

白色对象本来被一个灰色对象引用,但是该灰色对象将该引用赋给了黑色对象,灰对白的引用断开。此时,由于不会对黑色对象的引用进行检测标记,即该白色节点即使被引用也无法被标记为灰色,最终当作垃圾处理掉。


三色标记法出现对象丢失,要满足以下两个条件:

  • 条件一:白色对象被黑色对象引用
  • 条件二:灰色对象与白色对象之间的可达关系遭到破坏

只要破坏两个中的任何一个不会导致对象丢失的发生。

如何破坏两个条件

  • 强不变式: 不允许黑色对象引用白色对象
  • 弱不变式: 黑色对象可以引用白色对象,但是白色对象必须直接或间接被灰色对象引用。(保证白色对象一定会被扫描到)

go对上述规则的两种实现机制

插入写屏障
当一个A对象引用另外一个B对象时,将A对象标记为灰色。(就会再次被扫描)

插入屏障仅会在堆内存中生效,不对栈内存空间生效,这是因为go在并发运行时,大部分的操作都发生在栈上,函数调用会非常频繁。数十万goroutine的栈都进行屏障保护自然会有性能问题。

如果一个栈对象 黑色引用白色对象,白色对象依然会被当作垃圾回收。
因此,最后还需要对栈内存 进行STW,重新rescan,确保所有引用的被引用的栈对象都不会被回收。

删除写屏障
当一个白色对象被另外一个对象时解除引用时,将该被引用对象标记为灰色(白色对象被保护)

缺点:产生内存冗余,如果上述该白色对象没有被别的对象引用,相当于还是垃圾,但是这一轮垃圾回收并没有处理掉他。

四、混合写屏障法

  1. GC刚开始的时候,会将栈上的可达对象全部标记为黑色。

  2. GC期间,任何在栈上新创建的对象,均为黑色。将栈上的可达对象全部标黑,最后无需对栈进行STW,就可以保证栈上的对象不会丢失

  3. 堆上被删除的对象标记为灰色

  4. 堆上新添加的对象标记为灰色

五、总结

go 1.3 之前采用标记清除法,需要STW
go 1.5 采用三色标记法,插入写屏障机制(只在堆内存中生效),最后仍需对栈内存进行STW
go 1.8 采用混合写屏障机制,屏障限制只在堆内存中生效。避免了最后节点对栈进行STW的问题,提升了GC效率

# golang  

评论