go 高阶 の GC垃圾回收机制



一.历史原因

go发展史上采用过的一些方法

  • go 1.3 之前使用标记清除
  • go 1.5 三色标记法
  • go 1.8 三色标记法 + 混合写屏障机制

垃圾回收设计的名词

  • 自动释放
  • 垃圾回收
  • 三色标记法
  • 内存管理
  • SWT(stop the world) 全部停止执行



v1.3 之前的标记 - 清除方法

暂停程序业务逻辑,找出不可达的对象,和可达对象。

在这里插入图片描述
找到所有的可达对象,并做上标记。
在这里插入图片描述
标记完成以后,开始清楚未标记的对象
在这里插入图片描述
停止暂停,让程序继续跑,然后循环重复这个过程,直到 process 程序生命周期结束。



标记清除的缺点

  • STW:让程序暂停,程序出现卡顿(重要问题)
  • 标记需要扫描整个 heap
  • 清除数据会产生 heap 碎片
  • 将第三步和第四步调换位置,缩短 STW 的返回,但是还是会很大。


二.三色标记法

三色标记法的流程

只要是新创建的对象,默认颜色就是白色

在这里插入图片描述
第二步,每次 GC 回收开始,然后从根节点开始遍历所有对象,把遍历到的对象,从白色集合放入灰色集合
在这里插入图片描述
遍历灰色集合,将灰色对象的引用对象,从白色集合放入灰色集合,之后会将此灰色对象放入到黑色集合。
在这里插入图片描述
遍历上边的步骤,直到灰色节点里没有东西。
在这里插入图片描述


如果三色标记法不使用 STW 会出现的问题

在这里插入图片描述
如果三色标记法不被 STW 保护

  1. 一个白色对象被黑色对象引用
  2. 灰色对象与它之间的可达关系的白色对象遭到破坏
  3. 如果两个条件同时满足,那么就会出现对象丢失的现象


强弱三色不变式

  • 强制性的不允许黑色对象引用白色对象 :破坏了条件一
  • 黑色对象可以引用白色对象,但是要求白色对象的链路上游,存在灰色对象 :破坏了条件二
    在这里插入图片描述

只要满足了强三色不变式或者弱三色不变式之一,就可以保证对象不丢失。那么如何保证呢?就要借助于屏障机制。




三.屏障机制

屏障机制有点类似于其他语言的钩子函数,可以在不影响正常主程序正常使用的情况下,做一下额外的事情。有点类似于 vue 里面的声明周期函数

屏障机制
插入屏障
删除屏障
  • 插入屏障: 对象被引用时触发的机制
  • 删除屏障: 对象被删除时,触发的机制

插入屏障

具体操作: 将 B 挂载到 A 下游,B 必须被标记为灰色
满足了强三色不变式,不存在黑色对象引用白色对象的情况,因为白色会被强制编程灰色

注意,插入屏障,只是对 内的数据启动插入屏障,因为 的内存比较小,所以 不启动插入屏障,所以在回收白色节点之前,会对 中的数据重新扫描,并且加 STW 暂停保护栈,防止外界干扰。然后对 中的对象进行一次三色标记,直到没有灰色节点。

在这里插入图片描述

插入屏障存在的不足:
结束时,需要STW来重新扫描栈,大约需要10~100ms



删除屏障

被删除对象,如果自身为灰色或者白色,那么就被标记为灰色。
满足 弱三色不变式(保护灰色对象到白色对象的路径不会断)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

遍历灰色的标记,将可达对象,从白色标记为灰色,遍历灰色以后,就会将灰色标记黑色,

由上图可以看出,这种方法存在的问题

回收精度低,一个对象即使被删除了最后一个指向它的指针,也依然可以活过这一轮,在下一轮 GC 中被清理掉。

它之所以要这么做,就是为了防止在删除的时候,成为另一个对象的引用节点。



四. 三色标记法 + 混合写屏障

  1. GC 开始将栈上的可达对象全部扫描,并标记为黑色(这是一个前提,之后不再进行第二次重复扫描,无需 STW
  2. GC 期间,在栈上创建的新对象,均为黑色
  3. 被删除的对象标记为灰色
  4. 被添加的对象标记为灰色

栈不启用屏障,堆启用屏障

满足: 变形的弱三色不变式,(结合了插入、删除写屏障两者的优点)

在这里插入图片描述





四 总结

  • Go V1.3 中普通的标记清除法,整体过程需要 STW,效率极低
  • G0 V1.5 三色标记法,对空间启动写屏障,栈空间不启动,全部扫描之后,需要重新扫描一次栈(需要STW),效率普通
  • 三色标记法 + 混合写屏障机制,栈空间不启动,堆空间启动,整体过程几乎不需要 STW,效率极高。


查考文献

【1】https://www.bilibili.com/video/BV1wz4y1y7Kd?p=14&share_source=copy_web

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Golang是一种新兴的程序设计语言,被广泛应用于网络开发、云计算等领域。50k的高阶面试题对于不少求职者来说是一道难题,需要具备深厚的编程基础和实践经验,所以需要在以下几个方面下功夫: 1. 熟练掌握Golang的语法和特性,包括但不限于变量、函数、结构体、接口、包、并发等。透彻理解Golang的设计理念和哲学,掌握其优秀的并发性能和简洁的语法结构。 2. 掌握Golang的标准库和第三方库,并深入了解其内部实现和使用方法。掌握Golang的常用框架和工具,如Beego、Gin、Echo等,能够在实际工作中熟练使用。 3. 掌握Golang的性能优化和高可用架构设计,能够对应用程序进行优化,包括优化算法、内存管理、并发控制等方面。同时了解分布式系统、消息队列、容器化等技术,为应用程序提供高可用性和弹性。 4. 具备实际应用经验,能够解决实际工作中出现的各种问题。理解业务需求和用户体验,并能够为其提供创新的解决方案。 总之,要成为一名合格的Golang工程师,需要具备深厚的编程背景和实践经验。不断学习和深入掌握Golang的特性和应用场景,才能在高阶面试中获得成功。 ### 回答2: Golang 50K高阶面试题主要包括了Go语言的基础概念、并发编程、内存管理、网络等多个方面的考察。以下是对其中一些难点的简要解答。 并发编程: Go语言天生支持并发编程,因此并发编程是其核心优势之一。与其它编程语言不同,Go语言提供了一些内置的原语,如goroutine和channel,以便于编写并发代码。Goroutine是一个轻量级的线程,可与其他goroutine一起运行,而channel是用于在goroutine之间进行通信的并发安全的数据结构。通过这些特性,Go语言为开发并发程序提供了显着的便利。 内存管理: Go语言的内存管理是自动化的,开发者无需手动进行内存分配及释放。Go的垃圾回收机制可以自动检测不再使用的变量并将其回收,以便于再次利用。同时,Go语言还支持指针操作,但使用指针时需注意指针的生命周期以及指针空间的释放等问题,以免引起内存泄漏或者指针悬空等问题。 网络编程: Go语言提供了内置的网络库,能够轻松地进行TCP/IP和HTTP等协议的编程。与其它语言比较,Go语言提供了更高层次的API,使得开发网络应用变得更加简单,开发人员可以用更少更简洁的代码来实现同样的功能。 总的来说,Golang 50K高阶面试题主要考察了面试者在Go语言开发中的实际应用及其优势,特别是在并发编程、内存管理和网络编程等方面的应用。如果您希望在面试中表现更出色,需要熟练掌握Go语言的基本语法及其特性,并具有实际的项目经验。 ### 回答3: 首先,Golang 是一种高效、简洁、快速的编程语言,它在一定程度上成功地解决了传统语言的缺点,如并行编程的困难和内存泄漏等问题。而对于 Golang 高阶面试题,我们需要了解一些关键知识点。 首先是 Golang 的并发处理。Golang 的并发是基于 Goroutine 和 Channel 实现的,Goroutine 是轻量级线程,可以实现高度并发。而 Channel 是用来在 Goroutine 之间传递数据的通信机制。在面试中,常被问到如何确保 Goroutine 安全并实现并发。这时我们需要回答一些并发编程的关键问题,如共享资源、锁的使用和死锁避免等。 其次是 Golang 的内存管理。Golang 通过自动垃圾回收技术来实现内存管理和防止内存泄漏,而在面试中,常被问及如何避免内存泄漏,如何手动管理内存等问题,需要对 Golang 内存管理和垃圾回收机制有深入了解。 还有一些其他关键的问题,如异常处理和数据结构等,都需要我们进行深入学习和思考。在备战 Golang 的高阶面试时,除了掌握上述知识点外,还需要实践经验和多思考,不断完善自己的编程技能和能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值