添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
2021 -

Go GC

2023/2/22 Golang

​ 所有的编程语言都有内存的管理办法,这里面分两大类;一类是编程语言提供了手动管理内存的方式,开发者必须自行对内存进行申请和释放,虽然手动管理相对精准,但是编程麻烦且稍有不慎会造成内存泄露和指针乱踩的后果。另一类是由编程语言提供了垃圾收集机制,开发者不需要手动管理内存,这为开发者提供了很大的便利。

GC方法主要有以下三种

  • 标记-清除法(Golang)
  • 引用计数法
  • 分代收集(Java)

# Go V1.3 之前的标记清除法

标记清除法(mark and sweep) ,低版本的Go 采用的标记清除法很古老。原理也很简单。垃圾回收分为两个阶段: 标记阶段和清除阶段

  • 标记阶段:通过根节点(GC Roots)标记所有从根节点开始的对象,未被标记的对象就是未被引用的垃圾对象。
  • 清除阶段:清除所有未被标记的对象。
| --------------- Stop The World 暂停范围 -----------------|
|   启动STW   |   Mark标记  |  Sweep 清除   |    停止 STW   |
1
2

但是这样的垃圾回收机制造就了Golang被人诟病的两个槽点: 速度慢、效率差

STW(STOP THE WORLD)噩梦 ,在标记清除过程中,会进入一个 “Stop the World” 阶段, 当前运行的所有程序将被暂停。会导致性能下降。

另外标记阶段需要 扫描整个 heap ,复杂且消耗巨大,最后的清除阶段还会 造成heap碎片

# Go V1.5 三色标记法

三色标记法是逻辑上抽象出的三种状态。

  • 白色:对象未被标记,该对象将会在本次GC中被清理
  • 灰色:对象还在标记队列中等待
  • 黑色:对象已被标记,该对象不会在本次GC中被清理
  1. 初始状态下,所有的对象都是白色。

image-20230221221840108

  1. 从根节点开始遍历所有对象,把遍历到的对象变成灰色对象(备注:这里变成灰色对象的都是根节点的对象)。

image-20230221221904779

  1. 遍历灰色对象,将灰色对象引用的对象也变成灰色对象,然后将遍历过的灰色对象变成黑色对象。

image-20230221221942582

  1. 循环步骤3,直到灰色对象全部变黑色。
  2. 通过写屏障(write-barrier)检测对象有变化,重复以上操作
  3. 清除所有的白色对象。

以上图为例,最终对象6由于没有灰色对象引用,最终白色标记表里的对象6被当做 垃圾清除。

# 写屏障机制

下面主要解释一下步骤5 ,什么是” 写屏障机制(Write Barrier) “。

三色标记法在垃圾回收过程中是没有 STW 的 。程序在垃圾回收的同时也在正常运行中,为了防止一个被没有被引用的对象(实际上是本来被某对象引用但是取消了引用),在过程中又被已经标记为黑色对象引用,造成误清除,所以必须有一个保护机制即写屏障。

image-20230221221956156

如上图,对象2本引用对象三,但是GC过程中对象2放弃取消引用对象3,转为由对象4引用。那么对象4不会再被扫描,对象3无法变成灰色。

正是为了解决漏标的问题,需要使用写屏障机制来避免,写屏障一定是在内存进行写操作之前执行的。一般屏障机制需要满足以下两个原理来打破上面的破坏。

  • 强三色不变式 : 强制性的不允许黑色对象引用白色对象。
  • 弱三色不变式 :黑色对象可以引用白色对象,白色对象存在其他灰色对象对他的引用,或者可达它的链路上游存在灰色对象

image-20230221222004986

满足上述两种不变式才能做到GC过程中的误清除。

Go 语言使用两种写屏障技术,分别是 Dikstra 提出的插入写屏障和 Yuasa 提出的删除写屏障。

          —— 插入屏障  ...  对象被引用时触发