go内存逃逸和GC(垃圾回收)工作原理

go内存逃逸和GC(垃圾回收)工作原理

在go语言中,编译器通过逃逸分析决定变量的内存分配位置,这直接影响着程序的性能和内存使使用效率,

逃逸分析

Go逃逸分析最基本的原则是:如果一个函数返回对一个变量的引用,那么它就会发生逃逸。

任何时候,一个值被分享到函数栈帧范围之外,它都会在堆上被重新分配。

Go 语言GC(垃圾回收)的工作原理

答案
最常见的垃圾回收算法有标记清除(Mark-Sweep) 和引用计数(Reference Count),Go 语言采用的是标记清除算法。并在此基础上使用了三色标记法和写屏障技术,提高了效率。

标记清除收集器是跟踪式垃圾收集器,其执行过程可以分成标记(Mark)和清除(Sweep)两个阶段:

  • 标记阶段 --- 从根对象出发查找并标记堆中所有存活的对象;
  • 清除阶段 --- 遍历堆中的全部对象,回收未被标记的垃圾对象并将回收的内存加入空闲链表。

标记清除算法的一大问题是在标记期间,需要暂停程序(Stop the world,STW),标记结束之后,用户程序才可以继续执行。为了能够异步执行,减少 STW 的时间,Go 语言采用了三色标记法。

三色标记算法将程序中的对象分成白色、黑色和灰色三类。

  • 白色:不确定对象。
  • 灰色:存活对象,子对象待处理。
  • 黑色:存活对象。

标记开始时,所有对象加入白色集合(这一步需 STW )。首先将根对象标记为灰色,加入灰色集合,垃圾搜集器取出一个灰色对象,将其标记为黑色,并将其指向的对象标记为灰色,加入灰色集合。重复这个过程,直到灰色集合为空为止,标记阶段结束。那么白色对象即可需要清理的对象,而黑色对象均为根可达的对象,不能被清理。

三色标记法因为多了一个白色的状态来存放不确定对象,所以后续的标记阶段可以并发地执行。当然并发执行的代价是可能会造成一些遗漏,因为那些早先被标记为黑色的对象可能目前已经是不可达的了。所以三色标记法是一个 false negative(假阴性)的算法。

三色标记法并发执行仍存在一个问题,即在 GC 过程中,对象指针发生了改变。比如下面的例子:

|------------------------------------------|
| A (黑) -> B (灰) -> C (白) -> D (白) |

正常情况下,D 对象最终会被标记为黑色,不应被回收。但在标记和用户程序并发执行过程中,用户程序删除了 C 对 D 的引用,而 A 获得了 D 的引用。标记继续进行,D 就没有机会被标记为黑色了(A 已经处理过,这一轮不会再被处理)。

|-----------------------------------------|
| A (黑) -> B (灰) -> C (白) ↓ D (白) |

为了解决这个问题,Go 使用了内存屏障技术,它是在用户程序读取对象、创建新对象以及更新对象指针时执行的一段代码,类似于一个钩子。垃圾收集器使用了写屏障(Write Barrier)技术,当对象新增或更新时,会将其着色为灰色。这样即使与用户程序并发执行,对象的引用发生改变时,垃圾收集器也能正确处理了。

一次完整的 GC 分为四个阶段:

  • 1)标记准备(Mark Setup,需 STW),打开写屏障(Write Barrier)
  • 2)使用三色标记法标记(Marking, 并发)
  • 3)标记结束(Mark Termination,需 STW),关闭写屏障。
  • 4)清理(Sweeping, 并发)

参考内容:

Golang内存逃逸是什么?怎么避免内存逃逸?

逃逸分析对性能的影响

一文搞懂七种基本的GC垃圾回收算法

相关推荐
滕昕瑜16 分钟前
Pascal语言的操作系统安全
开发语言·后端·golang
冷琅辞2 小时前
Swift语言的跨平台开发
开发语言·后端·golang
东方苾梦2 小时前
Lua语言的安全开发
开发语言·后端·golang
慕离桑3 小时前
HTML语言的数据可视化
开发语言·后端·golang
能来帮帮蒟蒻吗3 小时前
GO语言学习(17)Gorm的数据库操作
开发语言·学习·golang
阮瑭雅5 小时前
Bash语言的微服务
开发语言·后端·golang
霍徵琅6 小时前
CSS语言的硬件驱动
开发语言·后端·golang
霍珵蕴6 小时前
Lisp语言的计算机视觉
开发语言·后端·golang
褚翾澜6 小时前
Lisp语言的无线通信
开发语言·后端·golang
甄霓裳6 小时前
APL语言的游戏音效
开发语言·后端·golang