【Golang】GC探秘/写屏障是什么?

之前写了 一篇【Golang】内存管理 ,有了很多的阅读量,那么我就接着分享一下Golang的GC相关的学习。

由于Golang的GC机制一直在持续迭代,本文叙述的主要是Go1.9版本及以后的GC机制,该版本中Golang引入了 混合写屏障大幅度地优化了STW的时间。具体GC机制的版本迭代可以参考 :GC的过去、现在和未来

基本概念

GC的对象

不再被需要的内存块,如果无法回收这部分内存将无法重复使用

内存泄漏

不再被需要的内存块,未在预期时间以内被回收的称为内存泄漏

常见的GC方法:

1.【PHP,Swift,Python等】引用计数法:

  • 每个对象维护一个自身被引用的次数,当一个引用者消息后该计数-1;
  • 它的优势为GC时查找需要回收的对象很简单:只需要找到引用计数为0的对象即可;
  • 它的劣势为在写入引用关系时需要额外维护引用计数,带来一定开销 ;
    2.【Golang】标记清除法:
  • 每次GC时通过从根对象出发递归地查询所有对象的引用关系,将无引用的对象进行标记后再行清理。
  • 它的优势在于写入引用关系时无额外开销
  • 它的劣势在于GC时查询引用关系有一定开销 ,有时还需要STW从而影响性能
STW: Stop the world

为了避免在GC的过程中,对象之间的引用关系发生新的变更使得GC的结果发生错误(比如GC过程中新增了一个引用,但是由于未扫描到该引用导致将被引用的对象清除了),停止所有正在运行的协程。

STW对性能有一些影响,Golang目前已经可以做到1ms以下的STW。

三色标记法

Golang中的GC方式为标记后清除,所采用的逻辑为------三色标记法:一开始全部的对象都是白色的


三色标记法

  1. 从root对象开始(全局变量+全局栈+当前活跃的goroutines中的栈),将它们加入到灰色队列中,进行遍历:类似于二叉树使用队列进行BFS遍历的过程
  2. 从灰色队列中pop出一个对象
  3. 将其引用的对象都置为灰色,加入到灰色队列中
  4. 将该对象置为黑色
  5. 直到灰色队列为空时,剩余的无引用的白色对象即会被清除

内存回收

看不太明白的可以参考我的上一篇文章:【Golang】内存管理

  1. 被回收的内存块会被回收到MCache(Processor私有内存)结构中 ,对应的MSpan(块类型)的allocBits的bitmap中对应的位置会被从1改为 0
  2. MSpan中除了allocBits还有另一个bitmap:GCMarkBits用于存放需要清除的标记:黑色=1,白色=0,一次GC之后所有MSpan中的GCMarkBits和AllocBits应该完全相同,因为只有黑色的内存对象在GC之后才会保留下来

写屏障

上文有提到为了避免GC的过程中新修改的引用关系到GC的结果发生错误,我们需要进行STW。但是STW会影响程序的性能,所以我们要通过写屏障技术尽可能地缩短STW的时间。

造成引用对象丢失的条件
  1. 一个黑色的节点A新增了指向白色节点C的引用
  2. 并且白色节点C没有除了A之外的其他灰色节点的引用,或者存在但是在GC过程中被删除了

以上两个条件需要同时满足:满足条件1时说明节点A已扫描完毕,A指向C的引用无法再被扫描到;满足条件2时说明白色节点C无其他灰色节点的引用了,即扫描结束后会被忽略 。

写屏障破坏两个条件其一即可
  1. 破坏条件1 => Dijistra写屏障
  • 满足强三色不变性:黑色节点不允许引用白色节点
  • 当黑色节点新增了白色节点的引用时,将对应的白色节点改为灰色
  1. 破坏条件2 => Yuasa写屏障
  • 满足弱三色不变性:黑色节点允许引用白色节点,但是该白色节点有其他灰色节点间接的引用(确保不会被遗漏)
  • 当白色节点被删除了一个引用时,悲观地认为它一定会被一个黑色节点新增引用,所以将它置为灰色
写屏障的分类

注意:由于栈上的操作需要保证性能,所以所有的写屏障均只针对堆上的对象。

写屏障的分类

GC的时机

  1. 每次内存分配时检查当前内存分配量是否已达到阈值(环境变量GOGC):默认100%,即当内存扩大一倍时启用GC
  2. 定时触发:当最近2分钟未触发过GC时,会触发一次GC
  3. 通过runtime.GC()手动触发

GC的优化

分配的对象越多,GC性能就越差,所以需要减少对象分配的个数,比如对象复用,使用sync.Pool

注意:sync.Pool类似于缓存,其中的对象会被定期清理(GC时清理),不能放置像是数据库连接这样需要稳定存储的数据

参考

1.三色标记法是什么?

2.Go语言垃圾收集器原理
最后编辑于:2025-02-05 20:55:05
© 著作权归作者所有,转载或内容合作请联系作者

喜欢的朋友记得点赞、收藏、关注哦!!!

相关推荐
JH30738 小时前
SpringBoot 优雅处理金额格式化:拦截器+自定义注解方案
java·spring boot·spring
qq_124987075311 小时前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
Coder_Boy_11 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
2301_8187320611 小时前
前端调用控制层接口,进不去,报错415,类型不匹配
java·spring boot·spring·tomcat·intellij-idea
汤姆yu15 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
暮色妖娆丶15 小时前
Spring 源码分析 单例 Bean 的创建过程
spring boot·后端·spring
点灯小铭16 小时前
基于51单片机的双档交流电压表设计与实现
单片机·嵌入式硬件·毕业设计·51单片机·课程设计·期末大作业
biyezuopinvip16 小时前
基于Spring Boot的企业网盘的设计与实现(任务书)
java·spring boot·后端·vue·ssm·任务书·企业网盘的设计与实现
JavaGuide17 小时前
一款悄然崛起的国产规则引擎,让业务编排效率提升 10 倍!
java·spring boot
清风66666617 小时前
基于单片机的智能电热水壶设计与温度控制系统
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业