Go GC垃圾回收机制

1、常见的GC实现方式有哪些?

常用的GC回收机制主要分追踪法、引用计数法这两大类。
引用计数法 ,就是每次被引用就加一,被取消引用就减一,当为零时,就可以清除掉。

Python就主要用的是引用计数法,优点是快,且方便。但缺点是,两个指针相互引用时,就会发生内存泄露。

追踪法是从根Root节点开始,遍历所有存活的对象,没被遍历到的就是可以清除掉的。而 GO 语言使用的就是标记追踪法。

2、Go语言的 GC使用的是什么?

Go 语言目前使用的就是,能够并发执行,的三色标记算法。

也就是能够从根开始遍历的标记-清除算法。

3、三色标记法是什么?

三色标记法是GC垃圾回收的核心算法。通过3种颜色,代表三种状态。
白色 :未被访问过的对象,标记阶段结束后,会被删除。
灰色 :已经被访问,但其引用的对象还没有被访问,会将该对象置为灰色。是待处理队列。
黑色 :已经被访问,且直接引用的对象也被访问过,则将其置为黑色。是确定存活队列。
标记流程:

开始的时,所有对象都是白色。先取出所有根Root对象,然后将其标记灰色,放到等待队列中。

之后,就从等待队列中取出一个灰色对象,若其引用的对象是白色,就置灰并放到等待队列中。直到其所有引用的对象全部被遍历过,然后将灰色对象变为黑色,放到以确定存活队列中。最后在将所有白色对象给清除掉。

4、Go 语言GC的根对象到底是什么?

GC的根对象,在GC中的术语叫做根集合。它是GC开始时,被扫描的第一批对象。
全局变量 :在程序编译期间,就已经被确定会在程序的整个生命周期存活的对象。
执行栈 :每个goroutine上都有一个执行栈,所有活跃的协程上的指针类型变量也会被视为根对象(map、slice...)。
寄存器:里面也存的值也能是指针,若其指向堆内对象,也会被视为根对象。

5、STW是什么?

STW,就是stop the world,它通常代表用户业务函数的停顿。一般会发生在 标记开始前的获取根对象时 与 开始标记结束后的收尾阶段。

6、并发标记清除的难点是什么?

难点就是,GC边标记对象,业务函数边执行时,造成GC标记错误,导致误删除了一些对象。

一般是发生在弱三色不变性的情况下。

7、Go语言是如何解决并发标记清除时,用户程序并发修改对象引用问题的?

Go语言通过 混合写屏障 配合 弱三色不变性 两者结合来实现的。

因为原本面对的问题 就是:

黑色对象,直接引用了白色对象。而白色对象与其被引用的灰色对象之间的连接断掉了。最终导致该白色对象可能会被误删。

混合写屏障解决的就是,堆内的对象被引用时,会将引用的对象所引用的旧对象保护起来置灰。然后新引用的对象也给保护起来置灰。

在标记结束前的STW阶段,再拿出来处理。从而避免了并发丢失白色对象问题。

8、什么是写屏障、混合写屏障如何实现?

写屏障就是编译器在执行指针操作时,会插入一段额外的逻辑,将被引用的对象保护起来。

说到混合写屏障,需要先分别知道增加写屏障删除写屏障

其中 增加写屏障 是对新增加的白色对象置为灰色,但它不官删除的对象。

而 删除写屏障 是对删除的对象置为灰色,但是它不官新增的对象。

混合写屏障 ,借鉴了两者的优点,对指针做出修改时,同时覆盖了新增删除两种场景。Go1.8也因为混合写屏障的优点,可以不用重新遍历栈,大大的降低了STW时间。

9、Go语言中 GC 的流程:

在标记前,先进行一次STW,获取所有的根对象集合。之后进行三色标记算法,同时并发执行业务函数,当标记阶段收尾时,再次启动一次很短的STW处理,被额外标记的堆对象,之后边执行业务函数,边并发清除垃圾对象。

10、GC 触发的时机有哪些?

主动触发:

  • 通过调用runtime.GC(),进行触发。

被动触发:

  • Go后台会有监控线程,一旦检测到堆内存是否触发了GC的阈值,来判断是否需要进行GC。
  • 第一次GC时,一旦堆内存达到4M就会自动触发。
  • 如果长达两分钟内未触发GC,那就自动触发。

11、GC 关注的指标有哪些?

  • CPU占比:CPU利用率一般要控制在5%以内。
  • GC停顿时间:一般由STW决定。(标记准备阶段,标记结束阶段)
  • GC停顿频率:看GC的次数,一般可以由GOGC与GOmemLimit控制。

12、有了 GC 为什么还会发生内存泄露?

内存泄露是区别内存逃逸的。所以需要先明白什么时内存泄露:

本来已经没用的内存,却还被引用着,导致GC无法清除。

  • 本来该释放的内存,却依旧被根对象引用。比如堆上没用的指针,却被全局map引用。
  • goroutine泄露,导致无法回收。

内存泄露是区别与内存逃逸的,内存逃逸是本来变量的生命周期是栈的,却意外跑到了堆上。

13、Go 的 GC如何调优?

1、可以减少的内存的分别,比如引入sync.Pool进行优化。

2、合理调节GOGC与GOMEMLimit这两个字段。

14、如何观察 Go GC?

powershell:

开始 $env:godebug:"gotrace=1"

go run main.go

取消 :remove-item env:godebug

powershell 复制代码
gc 1 @0.012s 1%: 0+1.0+0 ms clock, 0+0.52/2.6/0+0 ms cpu, 4->4->2 MB, 4 MB goal,
 0 MB stacks, 1 MB globals, 16 P

他们的含义分别是:

1、gc 1 第一个gc阶段

2、开始于程序启动0.012秒后

3、cpu利用率为1%

4、标记准备阶段0ms

5、并发标记阶段1.0ms

6、标记结束前的收尾阶段用了0ms

7、紧接着就是cpu相关的。这里不做解释。

8、4是标记开始前4MB堆内存。

9、4是标记结束时还是4MB内存。

10、清理后是2MB。

11、最第目标是剩余4MB。

当然,还可以通过pprof生产可视化界面进行操作。

相关推荐
y = xⁿ2 小时前
20天速通LeetCode day08:关于栈
算法·leetcode·职场和发展
Shadow(⊙o⊙)2 小时前
专题二滑动窗口
数据结构·算法
tankeven2 小时前
HJ181 相差不超过k的最多数
数据结构·c++·算法
donecoding2 小时前
类型与语法的“直觉对齐”:TS 切入的 Go 语言初体验
前端·typescript·go
XWalnut3 小时前
LeetCode刷题 day13
数据结构·算法·leetcode
审判长烧鸡3 小时前
GO闭包【3】闭包捕获
go·闭包·闭包捕获
炽烈小老头3 小时前
【每天学习一点算法 2026/04/17】多数元素
数据结构·学习·算法
审判长烧鸡3 小时前
Go闭包【2】 1.22 对 for 循环里闭包陷阱的那个“史诗级更新”
go·闭包
云泽8083 小时前
第十五届蓝桥杯大赛软件赛省赛C/C++大学B组
c语言·c++·算法·蓝桥杯