Goroutine Go 语言中 GC 的流程是什么?
Goroutine Go 语言中 GC 的流程是什么?
Go1.14 版本以 STW 为界限,可以将 GC 划分为五个阶段:
- GCMark 标记准备阶段,为并发标记做准备工作,启动写屏障
- STWGCMark 扫描标记阶段,与赋值器并发执行,写屏障开启并发
- GCMarkTermination 标记终止阶段,保证一个周期内标记任务完成,停止写屏 障
- GCoff 内存清扫阶段,将需要回收的内存归还到堆中,写屏障关闭 GCoff 内存归还阶段,将过多的内存归还给操作系统,写屏障关闭。
1 回复
在Go语言中,Goroutines是并发执行的基本单位,而垃圾回收(GC)是Go运行时(runtime)自动管理内存的一个重要部分。Go的GC机制设计得相对复杂但高效,主要基于三色标记-清除(Tri-color Marking)算法。下面简要介绍Go语言中GC的大致流程,并提供一些概念性的解释而非具体代码实现(因为GC的实现细节在Go的源码中,并且可能会随着版本更新而变化)。
Go GC 流程概览
-
标记阶段(Mark Phase)
- 停止世界(Stop-The-World, STW):在标记的初始阶段,为了获取一个一致的内存视图,Go的GC会暂时停止所有用户Goroutines的执行(即STW)。这个阶段的时间通常很短。
- 根对象标记:GC从一组预先确定的根对象(如全局变量、活跃的Goroutine栈上的变量等)开始,标记这些对象为存活。
- 三色标记:
- 白色:未访问的对象。
- 灰色:已被访问但尚未检查其引用的对象。
- 黑色:已被访问且其引用也已检查的对象。
- 遍历灰色对象,将其标记为黑色,并将其引用的对象标记为灰色。这个过程会递归进行,直到没有灰色对象为止。
-
标记终止(Mark Termination)
- 当没有更多的灰色对象时,标记阶段完成。此时,所有从根可达的对象都被标记为黑色或灰色,而白色对象则是垃圾,可以被回收。
-
清除阶段(Sweep Phase)
- 清除阶段并行进行,不会停止世界。GC遍历堆内存,回收所有白色对象占用的空间,并准备这些空间以供将来使用。
- 清除过程中,可能会遇到仍然被灰色或黑色对象引用的白色对象(由于并发性质)。Go的GC设计有写屏障(Write Barrier)来处理这种情况,确保对象引用的准确性。
-
结束与下一次GC的准备
- 清除完成后,GC结束,用户Goroutines恢复执行。
- Go的GC还实现了基于堆大小和分配频率的自动触发机制,以决定何时开始下一次GC。
示例代码(概念性)
由于GC是自动且内置的,没有直接控制GC流程的用户代码。但你可以通过runtime
包来查看或影响GC的行为,例如:
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
// 强制触发GC
runtime.GC()
// 获取当前Goroutine的数量
fmt.Println("Goroutines:", runtime.NumGoroutine())
// 设置GC的目标百分比(不推荐在生产环境中这样做)
// 注意:这仅是一个示例,实际设置需要谨慎
// runtime.SetGCPercent(200) // 设置GC启动的堆增长率为200%
// 模拟一些工作
go func() {
for {
time.Sleep(time.Second)
// 分配一些内存(例如,通过创建切片或映射)
}
}()
// 主Goroutine等待,让其他Goroutine运行
select {}
}
请注意,直接控制GC的参数(如SetGCPercent
)可能会对程序的性能产生显著影响,通常不建议在生产代码中修改这些设置。