Golang GC原理

Golang 从诞生之处到现在对GC做了诸多改进,目前用的GC算法为三色标记算法。

基础知识

在说三色标记算法之前,必须要了解一些基本的概念,否则无法真正理解Golang的GC算法

通常,一个垃圾回收器的执行过程被分为两个部分。

  • 赋值器:程序中的代码,对于垃圾回收器而言,关注的对象之间的引用,这些相互之间的引用,就构成了一张有向图,操作对象,也就是操作对象之间的引用关系。

  • 回收器:负责垃圾回收,找到上述中的不被引用的对象,清除并回收内存。

另外一个需要了解的概念就是根对象(在垃圾回收机制中叫做根集合),他包括:

  • 全局变量:这些程序在编译期间就能够确定

  • 执行栈: Goroutine上包含的变量以及指向堆内存的指针等

  • 还有其他指向堆内存区块的指针等等。

STW

因为回收而暂停,在1.14之后已经不会出现。

常见的GC算法

主要分为两类:

  • 追踪式GC: 从根集合出发,逐层遍历对象的引用信息,找出保留的对象,回收所有可以回收的对象,GO、JAVA等都是用这种方式。

  • 引用式GC: 每个对象的引用都包含一个被引用的计数,当为0时,回收

三色标记法

如下图所示,三色标记法,规定了三种不同类型的对象:

  • 白色对象:未被回收器访问到的对象,在回收的初始阶段,所有的对象,均为白色,当回收结束后,白色对象均不可达,意味着将被回收。
  • 灰色对象:回收器访问到的对象,但回收器,需要对其中的一个或多个指针进行扫描,查看是否还能到达白色对象。
  • 黑色对象:回收器访问的对象,且不会到达白色对象,意味着是活跃的对象,不需要被清除。

查看回收现象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"os"
"runtime/trace"
)

func main() {

f, _ := os.Create("trace.out")

defer f.Close()

_ = trace.Start(f)

defer trace.Stop()

for i := 0; i < 100; i++ {
_ = make([]int, 10)
}

}
1
go tool trace trace.out

屏障机制

标记受到并发的影响,可能会导致对象错误回收,所以在此之前需要做一定的处理,屏障机制,类似一个钩子函数。

具体操作

1、GC开始将栈上的对象全部扫描并标记为黑色(之后不再进行第二次重复扫描,无需STW),
2、GC期间,任何在栈上创建的新对象,均为黑色。
3、被删除的对象标记为灰色。
4、被添加的对象标记为灰色。


Golang GC原理
https://www.xinyublog.com/golang/gc/
作者
蚂蚁
发布于
2021年8月16日
许可协议