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生产可视化界面进行操作。

相关推荐
秋天的怀念_David2 小时前
算法一千零一夜 · 第十三夜 幻方,武侠世界里的数学迷宫
java·程序人生·算法
秋天的怀念_David3 小时前
算法一千零一夜 · 第十四夜 幻方与奇妙的二进制
java·程序人生·算法
薛定e的猫咪3 小时前
(ICLR 2020)MAML 靠的不是快速学习,而是特征复用
人工智能·深度学习·学习·算法·机器学习
薛定e的猫咪4 小时前
(ICLR 2026)DF-META:面向 FJSP 的无导数元学习实例自适应调度
人工智能·深度学习·学习·算法·机器学习
Thinker QAQ4 小时前
并发编程(十一):Shared Memory 与 Message Passing——关系与组合使用
java·python·go·并发编程·shared memory·message passing
小羊没烦恼!5 小时前
异步编程:线程概述及使用
java·开发语言·mysql·算法·c#
wanderist.5 小时前
202609CSP认证P3
算法
云淡风轻~窗明几净6 小时前
角谷猜想最接近严格证明的测试 Version1.1.1
人工智能·算法·机器学习·图论
机器学习之心6 小时前
PINN × SVM × NSGA-II × 熵权TOPSIS:一套跑通「建模—优化—决策」的多目标优化框架
算法·机器学习·支持向量机
别动我齐刘海7 小时前
机器人 C++ / 系统联调补强2——异常处理、Protobuf
linux·c++·人工智能·学习·算法·机器学习·机器人