Golang 垃圾回收机制

学习 Go 语言中的各个版本的垃圾回收的机制。

1、Go V1.3 版本之前的标记清除(mark and sweep)

此版本的垃圾回收机制,一般分为以下四步:

1、暂停程序业务逻辑,找出不可达的对象以及可达的对象

2、开始标记,程序找出其所有可达的对象,并进行标记

3、标记完之后,开始清除未标记的对象

4、继续运行程序。循环以上的过程,知道程序的生命周期终止为止

但是相应的,V1.3 版本中的垃圾回收的问题也较大:

首先有个 STW 暂停程序,这会浪费大量的时间去处理垃圾回收,不利于效率的提升,其次每一次的标记需要扫描整个 Heap 堆区,而且清除相关的数据也会产生内存堆的碎片。

2、Go v1.5 版本的三色标记法

此时,垃圾回收机制将运行中的程序状态分为:白、黑、灰三种状态

1、每一步默认创建的对象均标记均为”白色”

2、每一次 GC 回收的时候,均会从根节点遍历所有的对象,而且把遍历的对象从白色的集合放入”灰色” 的集合中,遍历为非递归形式。

3、遍历灰色的集合,将灰色对象引用的对象从白色集合中放入灰色集合,然后将灰色对象放入黑色集合中。

4、重复第三步,直到灰色集合中中无任何对象。

5、回收所有白色集合中的对象,即回收垃圾。

但是此处有两个问题:

  • 1、如果黑色对象后之间引用指向一个白色的对象,那么在第二步的时候,此白色对象并不能进行相应的染色,所以说此处会导致白色对象被清除!

  • 2、如果之前白色对象被灰色对象引用,而在扫描时系统发生了故障,导致灰色对象引用白色对象的指针丢失,导致白色对象被清除。

所以这样也引入了相应的优化方法:插入屏障与删除屏障机制。

3、Go 插入写屏障、删除写屏障

​ 插入写屏障主要应用为:在强三色不变式下(黑色直接引用白色的对象),那么此时,使用插入写屏障机制,强行改写黑色引用对象白色为灰色。但是插入写屏障机制会有几个缺点:需要重新扫描栈,大约 10 ms ~ 100 ms,也消耗了相应的系统资源。

​ 删除写屏障主要应用为:在弱三色不变式下(黑色引用白色对象,白色对象其他上游的引用对象有灰色对象进行引用:解决方法之后写),其也存在相应的不足:回收精度低、一个对象即使被删除了最后一个指向它的指针也依旧能活过这一轮,在下一轮的 GC 中被清除。

4、Go V1.8 三色标记法与混合写屏障

​ 混合标记法其实很容易理解,就是把插入写屏障与删除写屏障混合起来进行使用,其相应的步骤如下:

1、在 Go GC 触发之前,递归扫描分配在栈上的对象,使栈上的对象全部标记为”黑色”(此处因为是标记为全部 “黑色”,所以不会使用 STW 机制)

2、在 Go GC 运行期间,如果往栈上插入对象,将栈上的对象全部标记为 “黑色”。

3、同理,在 Go GC 运行,所有往堆上插入或者删除的对象,都标记为 “灰色”

5、Go GC 性能不佳的原因

1、建立的 struct 对象过小,所以导致频繁的 GC 检查;

2、Go 文件中出现内存泄漏的问题。


Golang 垃圾回收机制
https://chaggle.github.io/2022/03/01/go/basic/GC/
作者
chaggle
发布于
2022年3月1日
许可协议