Goroutine Go 语言中 GC 的流程是什么?

发布于 1周前 作者 zlyuanteng 最后一次编辑是 5天前 来自 问答

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 流程概览

  1. 标记阶段(Mark Phase)

    • 停止世界(Stop-The-World, STW):在标记的初始阶段,为了获取一个一致的内存视图,Go的GC会暂时停止所有用户Goroutines的执行(即STW)。这个阶段的时间通常很短。
    • 根对象标记:GC从一组预先确定的根对象(如全局变量、活跃的Goroutine栈上的变量等)开始,标记这些对象为存活。
    • 三色标记
      • 白色:未访问的对象。
      • 灰色:已被访问但尚未检查其引用的对象。
      • 黑色:已被访问且其引用也已检查的对象。
    • 遍历灰色对象,将其标记为黑色,并将其引用的对象标记为灰色。这个过程会递归进行,直到没有灰色对象为止。
  2. 标记终止(Mark Termination)

    • 当没有更多的灰色对象时,标记阶段完成。此时,所有从根可达的对象都被标记为黑色或灰色,而白色对象则是垃圾,可以被回收。
  3. 清除阶段(Sweep Phase)

    • 清除阶段并行进行,不会停止世界。GC遍历堆内存,回收所有白色对象占用的空间,并准备这些空间以供将来使用。
    • 清除过程中,可能会遇到仍然被灰色或黑色对象引用的白色对象(由于并发性质)。Go的GC设计有写屏障(Write Barrier)来处理这种情况,确保对象引用的准确性。
  4. 结束与下一次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)可能会对程序的性能产生显著影响,通常不建议在生产代码中修改这些设置。

回到顶部