【golang】深入理解Go语言垃圾回收(GC)

垃圾回收

  • 垃圾回收
    • 版本1.3之前标记-清除(mark and sweep)算法
      • 标记-清除(mark and sweep)的缺点
    • 版本1.5的三色并发标记法
    • 没有STW的三色标记法
    • 屏障机制
      • 强-弱 三色不等式
      • 插入屏障
      • 删除屏障
    • 版本1.8的混合写屏障(hybrid write barrier)机制
      • 混合写屏障机制
    • 垃圾回收(GC)触发机制
    • 垃圾回收优化
    • 总结:

垃圾回收

垃圾回收(Garbage Collection,简称GC)是编程语言中提供的自动的内存管理机制,自动释放不需要的对象,让出存储器资源,无需程序员手动执行。

版本1.3之前标记-清除(mark and sweep)算法

步骤:

  • 标记(Mark phase)
  • 清除(Sweep phase)

总体思想就是:暂停程序业务逻辑,找出不可达的对象,然后做上标记。第二步,回收标记好的对象。

  1. mark and sweep算法在执行的时候,需要程序暂停!即STW(stop the world)。也就是说,这段时间程序会卡在哪儿。

  2. 开始标记,程序找出它所有可达的对象,并做上标记。如下图所示:
    在这里插入图片描述

  3. 标记完了之后,然后开始清除未标记的对象,结果如下:
    在这里插入图片描述

  4. 停止暂停,让程序继续跑。然后循环重复这个过程,直到process程序生命周期结束。

标记-清除(mark and sweep)的缺点

  • STW,stop the world;让程序暂停,程序出现卡顿(重要问题)
  • 标记需要扫描整个heap
  • 清除数据会产生heap碎片

版本1.3之前就是以上来实施的,流程为

在这里插入图片描述
版本1.3做了简单的优化,将STW提前,减少STW暂停的时间范围,如下所示

在这里插入图片描述

版本1.5的三色并发标记法

三色标记法 实际上就是通过三个阶段的标记来确定清楚的对象都有哪些。

具体步骤:

  1. 新创建的对象,默认的颜色都是标记为”白色“
    在这里插入图片描述
  2. 每次GC回收开始,然后从根节点开始遍历所有对象,把遍历到的对象从白色集合放入灰色集合。
    在这里插入图片描述
  3. 遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合。
    在这里插入图片描述
  4. 重复第三步,直到灰色中无任何对象
  5. 回收所有的白色标记表的对象,也就是回收垃圾
    在这里插入图片描述

Go是如何解决标记-清除算法中的卡顿STW问题的呢?

没有STW的三色标记法

如果三色标记法,标记法过程中不使用STW将会发生什么呢?

  1. 已经标记为灰色的对象2,有指针p指向白色的对象3
    在这里插入图片描述
  2. 在还没有扫描到对象2,已经标注为黑色的对象4,创建指针q,指向对象3
    在这里插入图片描述
  3. 于此同时对象2将指针p移除,对象3就被挂在了已经扫描完成的黑色的对象4下。
    在这里插入图片描述
  4. 正常执行算法逻辑,对象2,7标记为黑色,而对象3因为对象4已经不会再扫描,而等待被回收清除。
    在这里插入图片描述
  5. 对象3,这个被正常引用的对象,被无辜的清除掉了。

可以看出,有两个问题,在三色标记法是不希望被发生的

  • 条件1:一个白色对象被黑色对象引用(白色被挂在黑色下)
  • 条件2:灰色对象与它之间的可达关系的白色对象遭到破坏(灰色同时丢了该白色)

以上两个条件同时满足时,就会出现对象丢失现象。

为了防止这种现象的发生,最简单的方式就是STW,直接禁止掉其他用户程序对对象引用关系的干扰,但是STW的过程有明显的资源浪费,对所有的用户程序都有很大影响,如何能在保证对象不丢失的情况下合理的尽可能的提高GC效率,减少STW时间呢?

​ 答案就是, 那么我们只要使用一个机制,来破坏上面的两个条件就可以了.

屏障机制

破坏上面两个条件引出两种方式:

强-弱 三色不等式

  • 强三色不等式

不存在黑色对象引用到白色对象的指针。
在这里插入图片描述

  • 弱三色不等式

所有被黑色对象引用的白色对象都处于灰色保护状态

在这里插入图片描述

为了遵循上述的两个方式Go团队初步得到了如下具体的两种屏障方式“插入屏障”,“删除屏障”。

插入屏障

具体操作:在A对象应用B对象的时候,B对象被标记为灰色。(将B挂在A下游,B必须被标记为灰色)
满足强三色不等式(不存在黑色对象引用白色对象的情况了,因为白色会强制变成灰色)

伪码如下:

添加下游对象(当前下游对象slot, 新下游对象ptr) {   //1标记灰色(新下游对象ptr)   //2当前下游对象slot = 新下游对象ptr                    
}

场景:

A.添加下游对象(nil, B) //A 之前没有下游, 新添加一个下游对象B, B被标记为灰色
A.添加下游对象(C, B) //A 将下游对象C 更换为B, B被标记为灰色

​这段伪码逻辑就是写屏障,我们知道,黑色对象的内存槽有两种位置, .栈空间的特点是容量小,但是要求相应速度快,因为函数调用弹出频繁使用, 所以“插入屏障”机制,在栈空间的对象操作中不使用,而仅仅使用在堆空间对象的操作中。

  1. 程序起初创建,全部标记为白色,将所有对象放入白色对象中。
    在这里插入图片描述

  2. 遍历Root Set(非递归形式,只遍历一次),得到灰色节点
    在这里插入图片描述

  3. 遍历Grey灰色标记表,将可达的对象,从白色标记为灰色,遍历之后的灰色,标记为黑色
    在这里插入图片描述

  4. 由于并发特性,此刻外界相对象4添加对象8、对象1添加对象9,对象4在堆区,即将触发插入屏障机制,对象1不触发
    在这里插入图片描述

  5. 由于插入写屏障(黑色对象添加白色,将白色改为灰色),对象8变成灰色,对象9依然为白色
    在这里插入图片描述

  6. 继续循环上述流程进行三色标记,直到没有灰色节点
    在这里插入图片描述
    但是如果栈不添加,当全部三色标记扫描之后,栈上有可能依然存在白色对象被引用的情况(如上图对象中的9),所以要对栈重新进行三色标记扫描, 但这次为了对象不丢失, 要对本次标记扫描启动STW暂停. 直到栈空间的三色标记结束.

  7. 在准备回收白色前,重新遍历扫描一次栈空间。此时加STW暂停保护栈,防止外界干扰(有新的白色被黑色添加)
    在这里插入图片描述

  8. 在STW中,将栈中的对象一次三色标记,直到没有灰色节点
    在这里插入图片描述

  9. 停止STW
    在这里插入图片描述

  10. 清除白色
    在这里插入图片描述

最后将栈和堆空间 扫描剩余的全部 白色节点清除,这次STW大约的时间在10~100ms

删除屏障

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

伪代码:

添加下游对象(当前下游对象slot, 新下游对象ptr) {//1if (当前下游对象slot是灰色 || 当前下游对象slot是白色) {标记灰色(当前下游对象slot)     //slot为被删除对象, 标记为灰色}//2当前下游对象slot = 新下游对象ptr
}

场景:

A.添加下游对象(B, nil) //A对象,删除B对象的引用。 B被A删除,被标记为灰(如果B之前为白)
A.添加下游对象(B, C) //A对象,更换下游B变成C。 B被A删除,被标记为灰(如果B之前为白)

  1. 程序起初创建,全部标记为白色,将所有对象放入白色集合中。
    在这里插入图片描述
  2. 遍历Root Set(非递归形式,只遍历一次)得到灰色节点
    在这里插入图片描述
  3. 灰色对象1删除对象5,如果不触发删除写屏障,5-2-3路径与主链路断开,最后均会被清除
    在这里插入图片描述
  4. 触发删除写屏障 被删除的对象5,自身被标记为灰色
    在这里插入图片描述
  5. 遍历Grey 灰色标记表,将可达的对象,从白色标记为灰色,遍历之后的灰色,标记为黑色
    在这里插入图片描述
  6. 继续循环上述流程进行三色标记,直到没有灰色节点
    在这里插入图片描述
  7. 清除白色
    在这里插入图片描述

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

版本1.8的混合写屏障(hybrid write barrier)机制

插入写屏障和删除写屏障的短板:

  • 插入写屏障:结束时需要STW来重新扫描栈,标记栈上引用的白色对象的存活
  • 删除写屏障:回收精度低,GC开始时STW扫描堆栈来记录初始快照,这个过程会保护开始时刻的所有存活对象。

1.8版本引入了混合写屏障机制,避免了对栈re-scan的过程,极大的减少了STW的时间。结合了两者的优点。

混合写屏障机制

具体操作
1、GC开始将栈上可达的对象全部扫描并标记为黑色(之后不再进行第二次重复扫描,无需STW)
2、GC期间,任何在栈上创建的新对象,均为黑色
3、被删除的对象标记为灰色
4、被添加的对象标记为灰色

注意:3、4点是触发写屏障,而触发写屏障只发生在堆结构中。

伪代码:

添加下游对象(当前下游对象slot, 新下游对象ptr) {//1 标记灰色(当前下游对象slot)    //只要当前下游对象被移走,就标记灰色//2 标记灰色(新下游对象ptr)//3当前下游对象slot = 新下游对象ptr
}

GC开始:扫描栈区,将可达对象全部标记为黑

  1. GC刚刚开始,默认都为白色
    在这里插入图片描述
  2. 三色标记法,优先扫描全部栈对象,将可达对象均标记为黑。
    在这里插入图片描述

场景一:对象被一个堆对象删除引用,成为栈对象的下游

//前提:堆对象4->对象7 = 对象7; //对象7 被 对象4引用
栈对象1->对象7 = 堆对象7; //将堆对象7 挂在 栈对象1 下游
堆对象4->对象7 = null; //对象4 删除引用 对象7

在这里插入图片描述
在这里插入图片描述
场景二: 对象被一个栈对象删除引用,成为另一个栈对象的下游

new 栈对象9;

对象8->对象3 = 对象3; //将栈对象3 挂在 栈对象9 下游 对象2->对象3 = null; //对象2
删除引用 对象3

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
场景三:对象被一个堆对象删除引用,成为另一个堆对象的下游

堆对象10->对象7 = 堆对象7; //将堆对象7 挂在 堆对象10 下游

堆对象4->对象7 = null; //对象4 删除引用 对象7

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

场景四:对象从一个栈对象删除引用,成为另一个堆对象的下游

堆对象10->对象7 = 堆对象7; //将堆对象7 挂在 堆对象10 下游

堆对象4->对象7 = null; //对象4 删除引用 对象7

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Golang中的混合写屏障满足弱三色不变式,结合了删除写屏障和插入写屏障的优点,只需要在开始时并发扫描各个goroutine的栈,使其变黑并一直保持,这个过程不需要STW,而标记结束后,因为栈在扫描后始终是黑色的,也无需再进行re-scan操作了,减少了STW的时间。

垃圾回收(GC)触发机制

  1. 内存分配量达到阈值:每次内存分配都会检查当前内存分配量是否达到阈值,如果达到阈值则触发GC。阈值 = 上次 GC 内存分配量 * 内存增长率,内存增长率由环境变量GOGC控制,默认为100,即每当内存扩大一倍时启动GC。
  2. 定时触发GC:默认情况下,2分钟触发一次GC,该间隔由src/runtime/proc.goforcegcperiod 声明。
  3. 手动触发GC:在代码中,可通过使用runtime.GC() 手动触发GC。

垃圾回收优化

  1. 控制内存分配的速度,限制goroutine的数量,从而提高赋值器对CPU的利用率。
  2. 减少并复用内存,例如使用sync.Pool来复用需要频繁创建的临时对象,例如提前分配足够的内存来降低多余的拷贝。
  3. 需要时,增大GOGC的值,降低GC的运行效率

总结:

  • GoV1.3-普通标记清楚法,整体过程需要启动STW,效率极低
  • GoV1.5-三色标记法,堆空间启动写屏障,栈空间不启动,全部扫描后,需要重新扫描一次栈(需要STW),效率普通
  • GoV1.8-三色标记法,混合写屏障,栈空间不启动,堆空间启动。整个过程几乎不需要STW,效率较高

文章参考:刘丹冰–《Go修养之路》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/141794.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【计算机网络】——数据链路层(应用:局域网、广域网、设备 )

//仅做个人复习和技术交流,图片取自王道考研,侵删 一、大纲 1、介质访问控制 信道划分介质访问控制 随机访问介质访问控制 2、局域网 3、广域网 4、数据链路层设备 二、局域网 1、局域网基本概念和体系结构 局域网(LocalArea Network): 简称LAN&…

[maven] 实现使用 plugin 及 properties 简述

[maven] 实现&使用 plugin 及 properties 简述 这章内容,我个人感觉可看可不看……? 不过课都上了,笔记 📒 补完才对得起自己嘛 plugins 主要讲一下 maven 的 plugin 时怎么实现的,以及项目中怎么调用自己实现…

实现电商跨平台订单每日自动对账

场景描述: 多数商家都存在多电商平台同时经营的情况,而进行订单对账则是相关业务或财务人员的每日必修课。比如商家在天猫,苏宁,1号店,京东等均有运营店铺,每天需要通过各电商后台系统抓单打单&#xff0c…

若依cloud -【 100 ~ 103 】

100 分布式日志介绍 | RuoYi 分布式日志就相当于把日志存储在不同的设备上面。比如若依项目中有ruoyi-modules-file、ruoyi-modules-gen、ruoyi-modules-job、ruoyi-modules-system四个应用,每个应用都部署在单独的一台机器里边,应用对应的日志的也单独存…

springboot如何接入netty,实现在线统计人数?

springboot如何接入netty,实现在线统计人数? Netty 是 一个异步事件驱动的网络应用程序框架 ,用于快速开发可维护的高性能协议服务器和客户端。 Netty ​ 是一个 NIO 客户端服务器框架 ​,可以快速轻松地开发协议服务器和客户端等…

微表情识别API + c++并发服务器系统

微表情识别API c并发服务器系统 该项目只开源c并发服务器程序,模型API部分不开源 地址:https://github.com/lin-lai/-API- 更新功能 4.1版本 改用epoll实现IO多路复用并发服务器 项目介绍 本项目用于检测并识别视频中人脸的微表情 目标任务: 用户上…

【李沐深度学习笔记】线性代数

课程地址和说明 线性代数p1 本系列文章是我学习李沐老师深度学习系列课程的学习笔记,可能会对李沐老师上课没讲到的进行补充。 线性代数 标量 标量(scalar),亦称“无向量”。有些物理量,只具有数值大小&#xff0c…

基于微信小程序的校园失物招领系统设计与实现(源码+lw+部署文档+讲解等)

前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 👇🏻…

Qt创建线程(使用moveToThread方法创建子线程)

1.moveTothread方法: (1)要使用moveToThread方法必须继承与QObject类 (2)创建任务对象时不能指定父对象 例子: MyWork* work new MyWork(this); // error MyWork* work new MyWork; // ok (3&#…

北工大汇编题——分支程序设计

题目要求 信息检素程序设计:在数据区,有9个不同的信息,编号 0-8,每个信息包括20 个字符。从键盘接收 0-8 之间的一个编号,然后再屏幕上显示出相应编号的信息内容,按“q”键退出 完整代码 DATAS SEGMENTn0…

搭建SpringBoot项目三种方式(超详细版)

目录 一、官网下载压缩包解压 二、通过Idea脚手架搭建 三、Spring Boot项目结构 3.1 pom.xml文件 3.2 启动类 3.3 配置文件 四、通过创建Maven项目添加依赖 一、官网下载压缩包解压 接下来我们搭建一个SpringBoot项目,并引入SpringMVC的功能,首先…

自学WEB服务器搭建01-安装Express+Node.js框架完成Hello World!

一、前言,网站开发扫盲知识 1.网站搭建开发包括什么? 前端、后端(服务端)数据库 前端开发主要涉及用户界面(UI)和用户体验(UX),负责实现网站的外观和交互逻辑。前端开发…

多线程进阶:常见的锁策略、CAS

之前我们所了解的属于多线程的初阶内容。今天开始,我们进入多线程进阶的学习。 锁的策略 乐观锁 悲观锁 这不是两把具体的锁,应该叫做“两类锁” 乐观锁:预测锁竞争不是很激烈(这里做的工作可能就会少一些) 悲观锁…

3.6+铁死亡+WGCNA+机器学习

今天给同学们分享一篇3.6铁死亡WGCNA机器学习的生信文章“Identification of ferroptosis related biomarkers and immune infiltration in Parkinsons disease by integrated bioinformatic analysis”,这篇文章于2023年3月14日发表在BMC Med Genomics期刊上&#…

Mac电脑信息大纲记录软件 OmniOutliner 5 Pro for Mac中文

OmniOutliner 5 Pro是一款专业级的Mac大纲制作工具,它可以帮助用户更好地组织和管理信息,以及制作精美的大纲。以下是OmniOutliner 5 Pro的主要功能和特点: 强大的大纲组织和管理功能。OmniOutliner 5 Pro为用户提供了多层次的大纲结构&…

【QT】QT事件Event大全

很高兴在雪易的CSDN遇见你 ,给你糖糖 欢迎大家加入雪易社区-CSDN社区云 前言 本文分享QT中的事件Event技术,主要从QT事件流程和常用QT事件方法等方面展开,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞关注,小易…

virtualbox安装linux虚拟机访问互联网(外网)的方法

virtualbox安装linux虚拟机访问互联网(外网)的方法 设置方法效果图 设置方法 效果图

Linux系统编程-文件

目录 1、系统编程介绍以及文件基本操作文件编程系统调用文件基本读写练习 2、文件描述符以及大文件拷贝文件描述符大文件拷贝对比试验 3、文件实战练习 1、系统编程介绍以及文件基本操作 系统编程是基于Linux封装好的一些函数,进行开发。 Linux文件信息属性在indo…

用AI解决量子学问题

3 人工智能用于量子力学 在这一部分中,我们提供了有关如何设计高级深度学习方法以有效学习神经波函数的技术评述。在第3.1节中,我们概述了一般情况下定义和解决量子多体问题的方法。在第3.2节中,我们介绍了学习量子自旋系统基态的方法。在第…

微信收款码费率0.38太坑了

作为一个有多年运营经验的商家,我本人在申请收款功能时曾经走过了不少弯路。我找遍了市面上的知名的支付公司,但了解到的收款手续费率通常都在0.6左右,最低也只能降到0.38。这个过程吃过不少苦头。毕竟,收款功能是我们商家的命脉&…