Golang Go语言中 GC 为什么需要等到所有 goroutine 停止才能够开始?

发布于 1周前 作者 eggper 来自 Go语言

我正在实现一个并发的三色标记垃圾收集器,我看了一些帖子,里面描述的 1.14 之前,golang 无法强制停止 goroutine 从而无法启动开始 gc 。

我的疑问是,全局变量 runtime.writeBarrier 更新了之后,运行中的 goroutine 不就读到了 writeBarrier 并启动了写屏障么,为什么必须等待 goroutine 停止呢?

92 CMPL runtime.writeBarrier(SB), $0
99 JEQ 103
101 JMP 108
108 CALL runtime.gcWriteBarrier(SB)



更近一步,假设刚刚更新完读不到,那更新完等个几十 ms 还读不到么 🤔.
Golang Go语言中 GC 为什么需要等到所有 goroutine 停止才能够开始?


更多关于Golang Go语言中 GC 为什么需要等到所有 goroutine 停止才能够开始?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

提高 gc 吞吐量。

更多关于Golang Go语言中 GC 为什么需要等到所有 goroutine 停止才能够开始?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


有种 atomic 的感觉

原则上可能是为了避免多线程竞争。

[粗线条话 GC (一)] https://www.bilibili.com/video/BV1hv411x7we?p=19
我看这里有简单解释了一下,GC 开始前需要 STW 通知全部的 g 开启写屏障,没有 STW 的话可能会导致部分的 g 开启写屏障有延时导致错误。至于”1.14 之前,golang 无法强制停止 goroutine 从而无法启动开始 gc “是因为 1.13 之前是依赖编译期间插入的代码来检测是否有 gc 在等待执行,如果代码中有个 for{}循环就会导致插入的代码无法执行,从而导致一直阻塞

貌似和多线程引用计数需要记录指针调用,如果线程运行中启动,可能会影响指针记录,造成内存泄漏,所以等 goroutine 结束再启动

在Go语言中,垃圾回收(GC)机制是运行时环境的一个重要组成部分,负责自动管理内存。关于GC为什么需要等到所有goroutine停止才能开始,这主要涉及到内存安全和一致性的考虑。

首先,GC过程中需要扫描和标记所有可达的内存对象,以确保不会被错误地回收。如果goroutine在GC过程中继续运行,它们可能会创建新的内存引用或修改现有的引用关系,这将导致GC过程无法准确判断哪些内存是可达的,从而可能引发内存泄漏或提前释放仍在使用的内存,造成程序崩溃或行为异常。

其次,GC过程通常涉及对内存堆的遍历和修改,这些操作在并发环境下很难保证安全性和一致性。为了确保GC过程的正确性和高效性,Go运行时选择在特定的时间点暂停所有goroutine,即STW(Stop The World)阶段,以提供一个稳定的内存状态供GC进行扫描和标记。

虽然STW阶段会导致程序运行短暂的停顿,但Go语言的GC算法经过不断优化,已经能够将这些停顿时间控制在毫秒级甚至更短,从而在保证内存管理效率的同时,尽量减少对程序性能的影响。

综上所述,Go语言中的GC需要等到所有goroutine停止才能开始,是为了确保内存管理的正确性和一致性,以及GC过程的安全性和高效性。

回到顶部