Go的GC垃圾回收机制

历史原因

  1. go发展史上采用过的一些方法
  • go 1.3 之前使用标记清除 (mark and sweep)

  • go 1.5 三色标记法

  • go 1.8 三色标记法 + 混合写屏障机制

  1. 垃圾回收设计的名词
  • 自动释放
  • 垃圾回收
  • 三色标记法
  • 内存管理
  • STW(stop the world) 全部停止执行

标记清除法

标记清除法过程

  1. 暂停程序业务逻辑
    暂停程序,绘制程序和对象的可达关系。这里的对象是个广义的概念,包括对象和变量或方法
  2. 找到所有的可达对象,并做上标记。


3. 清除未标记对象

  1. 停止暂停

停止暂停,让程序继续跑,然后循环重复这个过程,直到程序生命周期结束。

标记清除的缺点

  • STW(stop the world):让程序暂停,程序出现卡顿,影响性能(核心问题)

  • 标记需要扫描整个 heap(堆)

  • 清除数据会产生 heap 碎片

  • 可以对以上方法进行改进(如下图),缩短 STW 的返回,但是还是会很大。

三色标记法的流程

三色标记法中,要切记,灰色只是一种状态,我们进行遍历最后的结果,就是没有灰色节点。

创建程序

  1. 程序创建的时候,默认所有的对象都是白色。只要是新创建的对象,默认颜色就是白色

在这里插入图片描述
2. 遍历对象(非递归调用,只遍历一次),得到灰色节点

在这里插入图片描述

切记这里的遍历,是从根节点出发。遍历到 对象1对象4,切记 只遍历这一步,二不是递归调用。,他会把遍历到的 对象1对象4加入到灰色标记表中

  1. 遍历灰色集合
    对灰色节点进行遍历,把灰色几点能达到的点,标记为灰色节点,把自己标记为黑色节点。
    在这里插入图片描述

重复遍历灰色标记表,直到不存在灰色节点。

在这里插入图片描述

灰色标记表只是一种中间状态,最终我们要把灰色标记表中的东西全部清理掉。只剩下要么都是白的,要么都是黑的

  1. 回收白色垃圾

三色标记法不使用 STW 会出现的问题

说白了,他的问题就在于黑色节点引用白色节点了,这个白色节点,如果不停留,就会被删除掉。


在这里插入图片描述

综上所述,三色标记法最不希望发生的事

  1. 一个白色对象被黑色对象引用
  2. 灰色对象同时又丢了对该白色对象的引用

如果以上两个条件同时满足,那么就会出现对象丢失现象

强弱三色不变式

  • 强三色不变式: 强制性的不允许黑色对象引用白色对象 :破坏了条件一

  • 弱三色不变式: 黑色对象可以引用白色对象,但是要求白色对象的链路上游,存在灰色对象 :破坏了条件二
    在这里插入图片描述

只要满足了强三色不变式或者弱三色不变式其中任何一个条件,就可以保证对象不丢失。那么如何保证呢?就要借助于屏障机制。

屏障机制

什么是屏障

屏障就是相当于在正常的流程中,插入了一道工序,在某些个语言里,屏障也叫做 回调,Hook 或者 handler钩子函数

插入屏障和删除屏障

屏障机制在 go 语言里,分为两种,分别为 插入屏障删除屏障,由名字可知

  1. 插入屏障: 当一个对象被引用时,触发的机制
  2. 删除屏障: 一个对象被删除的时候,触发的机制

插入屏障

具体操作: 在 A 对象引用 B 对象的时候,B对象被标记为灰色。(将B挂在A下游,B必须标记为灰色)

这样可以满足强三色不变式,因为不存在黑色对象引用白色对象的情况了,因为白色会被强制编程灰色。

插入屏障的问题

因为每次引用对象,都触发 插入屏障 的话,会影响性能;堆栈两种结构相比,栈对性能的要求更高,所以为了不影响 上的性能,是不执行插入屏障的,只有在 上才执行插入屏障。

那么栈是如何进行垃圾回收的呢?

是在 上的数据都扫描完了以后,然后启动 STW,再重新扫描一遍,标记完以后,进行删除。

删除屏障

被删除的对象,如果自身是灰色或者白色,那么就会被标记为灰色(其实就是为了保护灰色的一轮)

满足: 弱三色不变式。(保护灰色对象到白色对象的路径不会断)

  1. 要删除对象2

  1. 对象2 删除以后,要把 对象2 变成灰色

  1. 接下来,把所有的白色对象删除掉。

从上边可以看出来,这样回收删不干净,部分节点要等第二轮CG才能删除

混合屏障

单独使用删除写屏障和插入写屏障存在的问题

插入写屏障的不足: 结束时,需要STW来重新扫描栈,大概需要 10~100ms
删除写屏障的不足:回收精度低,一个对象即使被删除了,最后一个指向它的指针,也依旧可以活过这一轮,

三色标记 + 混合写屏障

  1. GC开始,优先扫描栈,将栈上的可达对象全部扫描,并标记为黑色(之后不再进行第二次扫描,无需STW)。
  2. GC期间,在栈上创建的节点,也都是黑色。
  3. 被删除对象,标记为 灰色
  4. 被添加的节点,也标记为灰色

注意,为保证栈的性能,栈是不引入屏障机制的。删除对象就是添加一个nil对象,所以删除也叫删除写屏障。

参考文献

https://www.bilibili.com/video/BV1wz4y1y7Kd?share_source=copy_web

posted @ 2021-07-04 21:26  沧海一声笑rush  阅读(491)  评论(0)    收藏  举报