垃圾回收——三色标记法(golang使用)

news2025/4/9 9:52:57

三色标记法(tricolor mark-and-sweep algorithm)是传统 Mark-Sweep 的一个改进,它是一个并发的 GC 算法,在Golang中被用作垃圾回收的算法,但是也会有一个缺陷,可能程序中的垃圾产生的速度会大于垃圾收集的速度,这样会导致程序中的垃圾越来越多无法被收集掉。

三种颜色的含义:

白色(White):表示未被访问的对象。在垃圾回收开始时,所有对象最初都被标记为白色。

灰色(Gray):表示正在被访问但尚未访问完的对象。当一个对象被访问时,它从白色变为灰色。

黑色(Black):表示已经访问完毕的对象,即所有可达子对象都已被访问。

原理与步骤

无写屏障的步骤

第一步 , 就是只要是新创建的对象,默认的颜色都是标记为“白色”.
第二步, 每次GC回收开始, 然后从根节点开始遍历所有对象,把遍历到的对象从白色集合放入“灰色”集合。
第三步, 遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合
第四步, 重复第三步, 直到灰色中无任何对象.
第五步: 回收所有的白色标记表的对象. 也就是回收垃圾.

有写屏障的步骤

step 1: 创建:白、灰、黑 三个集合。

step 2: 将所有对象放入白色集合中。

step 3: 从根节点开始遍历所有对象,把遍历到的对象从白色集合放入灰色集合(备注:这里放入灰色集合的都是根节点的对象)。

step 4: 遍历灰色集合,将灰色对象引用的对象(备注:这里指的是灰色对象引用到的所有对象,包括灰色节点间接引用的那些对象)从白色集合放入灰色集合,然后将分析过的灰色对象放入黑色集合。

step 5: 直到灰色中无任何对象。

step 6: 通过写屏障(write-barrier)检测对象有变化,重复以上操作(备注:因为 mark 和用户程序是并行的,所以在上一步执行的时候可能会有新的对象分配,写屏障是为了解决这个问题引入的)。

step 7: 收集所有白色对象(垃圾)。

具体例子

  1. 初始阶段,假设当前的对象调用情况如下所示,root ->A->B/A->C/A<->D;root->F; E; G->H;
    在这里插入图片描述

根据算法,会将所有的对象都放到白色集合当中,对应于step 1和step 2。

  1. GC开始扫描,这里会从根节点开始,遍历发现只有A和F是根节点,于是将A、F从白色集合移动到灰色集合当中,在白色结合中之后剩下B、C、D、E、G、H这些节点,对应于step 3。
    在这里插入图片描述
  2. GC继续扫描灰色集合,会将灰色集合中的节点中引用的节点移动到灰色集合当中,本例中A节点引用的节点B、C、D会被移动到灰色集合中,紧接着A发现自己引用的所有子节点都已经在灰色集合了,便会被移动到黑色集合中,同时F节点没有自节点,也会被移动到黑色集合当中,对应于step 4。
    在这里插入图片描述
  3. GC会循环遍历灰色集合,直到灰色集合之中没有节点为止,在本例中,发现B、C、D都没有子节点在白色集合中,便将B、C、D都移动到黑色集合中,对应于step 5。
    在这里插入图片描述
  4. 此时只剩下E、G、H在白色集合中,剩下的对象都在黑色集合中,GC便清除白色集合中的对象,也就是进行回收这些对象,对应于step 7
    在这里插入图片描述
  5. 上面的垃圾回收结束之后,GC会在进行一步操作,也就是将黑色集合变色成白色集合,供下一次垃圾回收使用。
    在这里插入图片描述

需要暂停以进行垃圾回收——性能差

​ Golang中的垃圾回收主要应用三色标记法,GC过程和其他用户goroutine可并发运行,但需要一定时间的STW(stop the world),STW的过程中,CPU不执行用户代码,全部用于垃圾回收,这个过程的影响很大,Golang进行了多次的迭代优化来解决这个问题。

上述的三色并发标记法来说, 他是一定要依赖STW的. 因为如果不暂停程序, 程序的逻辑改变对象引用关系, 这种动作如果在标记阶段做了修改,会影响标记结果的正确性。

在三色标记法中,导致对象丢失的有两个条件:

  • 条件1: 一个白色对象被黑色对象引用**(白色被挂在黑色下)**
  • 条件2: 灰色对象与它之间的可达关系的白色对象遭到破坏**(灰色同时丢了该白色)**
    当以上两个条件同时满足时, 就会出现对象丢失现象!

​当然, 如果上述中的白色对象3, 如果他还有很多下游对象的话, 也会一并都清理掉.

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

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

如何优化 屏障机制

“强-弱” 三色不变式

我们让GC回收器,满足强/弱三色不变式时,可保对象不丢失

强三色不变式:不存在黑色对象引用到白色对象的指针。

在这里插入图片描述

弱三色不变式:所有被黑色对象引用的白色对象都处于灰色保护状态.

在这里插入图片描述
为了遵循上述的两个方式,Golang团队初步得到了如下具体的两种屏障方式“插入屏障”, “删除屏障”.

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

2.3 删除屏障
具体操作: 被删除的对象,如果自身为灰色或者白色,那么被标记为灰色。

满足: 弱三色不变式. (保护灰色对象到白色对象的路径不会断)

在这里插入图片描述
伪代码:

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

A.添加下游对象(B, nil) //A对象,删除B对象的引用。 B被A删除,被标记为灰(如果B之前为白)
A.添加下游对象(B, C) //A对象,更换下游B变成C。 B被A删除,被标记为灰(如果B之前为白)
这种方式的回收精度低,一个对象即使被删除了最后一个指向它的指针也依旧可以活过这一轮,在下一轮GC中被清理掉。

2.4 插入写屏障和删除写屏障的短板
插入写屏障:结束时需要STW来重新扫描栈,标记栈上引用的白色对象的存活;
删除写屏障:回收精度低,GC开始时STW扫描堆栈来记录初始快照,这个过程会保护开始时刻的所有存活对象。
Go V1.8版本引入了混合写屏障机制(hybrid write barrier),避免了对栈re-scan的过程,极大的减少了STW的时间。结合了两者的优点。

3 混合写屏障(hybrid write barrier)
3.1 混合写屏障规则
具体操作:

GC开始将栈上的对象全部扫描并标记为黑色(之后不再进行第二次重复扫描,无需STW),
GC期间,任何在栈上创建的新对象,均为黑色。
堆中,被删除的对象标记为灰色。
堆中,被添加的对象标记为灰色。
满足: 变形的弱三色不变式.

伪代码:

添加下游对象(当前下游对象slot, 新下游对象ptr) {
//1
标记灰色(当前下游对象slot) //只要当前下游对象被移走,就标记灰色
//2
标记灰色(新下游对象ptr)
//3
当前下游对象slot = 新下游对象ptr
}
这里我们注意, 屏障技术是不在栈上应用的,因为要保证栈的运行效率。
3.2 混合写屏障的具体场景分析
接下来,我们用几张图,来模拟整个一个详细的过程, 希望您能够更可观的看清晰整体流程。

注意混合写屏障是Gc的一种屏障机制,所以只是当程序执行GC的时候,才会触发这种机制。
GC开始:扫描栈区,将可达对象全部标记为黑

在这里插入图片描述

参考资料和更多详细的看

https://zhuanlan.zhihu.com/p/14541819173

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows环境下开发pyspark程序

Windows环境下开发pyspark程序 一、环境准备 1.1. Anaconda/Miniconda&#xff08;Python环境&#xff09; 如果不怕包的版本管理混乱&#xff0c;可以直接使用已有的Python环境。 需要安装anaconda/miniconda&#xff08;python3.8版本以上&#xff09;&#xff1a;Anaconda…

SSM婚纱摄影网的设计

&#x1f345;点赞收藏关注 → 添加文档最下方联系方式咨询本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345; 项目视频 SS…

1110+款专业网站应用程序UI界面设计矢量图标figma格式素材 Icon System | 1,100+ Icons Easily Customize

1110款专业网站应用程序UI界面设计矢量图标figma格式素材 Icon System | 1,100 Icons Easily Customize 产品特点 — 24 x 24 px 网格大小 — 2px 线条描边 — 所有形状都是基于矢量的 — 平滑和圆角 — 易于更改颜色 类别 &#x1f6a8; 警报和反馈 ⬆️ 箭头 &…

Llama 4 家族:原生多模态 AI 创新的新时代开启

0 要点总结 Meta发布 Llama 4 系列的首批模型&#xff0c;帮用户打造更个性化多模态体验Llama 4 Scout 是有 170 亿激活参数、16 个专家模块的模型&#xff0c;同类中全球最强多模态模型&#xff0c;性能超越以往所有 Llama 系列模型&#xff0c;能在一张 NVIDIA H100 GPU 上运…

正则表达式(Regular Expression,简称 Regex)

一、5w2h&#xff08;七问法&#xff09;分析正则表达式 是的&#xff0c;5W2H 完全可以应用于研究 正则表达式&#xff08;Regular Expressions&#xff09;。通过回答 5W2H 的七个问题&#xff0c;我们可以全面理解正则表达式的定义、用途、使用方法、适用场景等&#xff0c…

JMeter脚本录制(火狐)

录制前准备&#xff1a; 电脑&#xff1a; 1、将JMeter证书导入&#xff0c;&#xff08;bin目录下有一个证书&#xff0c;需要安装这个证书到电脑中&#xff09; 2、按winr&#xff0c;输入certmgr.msc&#xff0c;打开证书&#xff0c;点击下一步&#xff0c;输入JMeter证书…

基于SpringBoot的“高校社团管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“高校社团管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 总体功能结构图 局部E-R图 系统首页页面 用户…

C# Winform 入门(3)之尺寸同比例缩放

放大前 放大后 1.定义当前窗体的宽度和高度 private float x;//定义当前窗体的宽度private float y;//定义当前窗台的高度 2.接收当前窗体的尺寸大小 x this.Width;//存储原始宽度ythis.Height;//存储原始高度setTag(this);//为控件设置 Tag 属性 3.声明方法&#xff0c;获…

infinityfree最新免费建站详细教程_无需备案_5G空间_无限流量_免费域名_免费SSL

一、明确目标—是否要使用 1.为什么选择InfinityFree&#xff1f; 对于初学者、学生或只是想尝试网站搭建的个人用户来说&#xff0c;InfinityFree提供了一个绝佳的免费解决方案。这个国外免费的虚拟主机服务提供&#xff1a; 5GB存储空间 - 足以存放个人博客、作品集或小型…

打造高效英文单词记忆系统:基于Python的实现与分析

在当今全球化的世界中,掌握一门外语已成为必不可少的技能。对于许多学习者来说,记忆大量的英文单词是一个漫长而艰难的过程。为了提高学习效率,我们开发了一个基于Python的英文单词记忆系统。这个系统结合了数据管理、复习计划、学习统计和测试练习等多个模块,旨在为用户提…

node_modules\deasync: Command failed.

运行&#xff1a;“yarn install” 时报错 PS D:\WebPro\hainan-mini-program> yarn install yarn install v1.22.19 [1/4] Resolving packages... [2/4] Fetching packages... [3/4] Linking dependencies... warning " > babel-loader8.2.2" has un…

游戏引擎学习第206天

回顾并为当天的工作定下目标 接着回顾了前一天的进展。之前我们做了一些调试功能&#xff0c;并且已经完成了一些基础的工作&#xff0c;但是还有一些功能需要继续完善。其中一个目标是能够展示实体数据&#xff0c;以便在开发游戏逻辑系统时&#xff0c;可以清晰地查看和检查…

Zapier MCP:重塑跨应用自动化协作的技术实践

引言&#xff1a;数字化协作的痛点与突破 在当今多工具协同的工作环境中&#xff0c;开发者与办公人员常常面临数据孤岛、重复操作等效率瓶颈。Zapier推出的MCP&#xff08;Model Context Protocol&#xff09;协议通过标准化数据交互框架&#xff0c;为跨应用自动化提供了新的…

蓝桥云客--破译密码

5.破译密码【算法赛】 - 蓝桥云课 问题描述 在近期举办的蓝桥杯竞赛中&#xff0c;诞生了一场激动人心的双人破译挑战。比赛的主办方准备了N块神秘的密码芯片&#xff0c;参赛队伍需要在这场智力竞赛中展示团队合作的默契与效率。每个队伍需选出一位破译者与一位传输者&#…

React-Diffing算法和key的作用

1.验证Diffing算法 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </he…

【NLP 54、大模型训练相关知识】

目录 引言&#xff1a;大模型训练两大问题 一、并行训练 1.方式一&#xff1a;数据并行 DP ① 复制模型到多个GPU ② 各自计算梯度后累加&#xff0c;再反传更新 ③ 需要单卡就能训练整个模型&#xff08;显存够大&#xff09; 2.方式二&#xff1a;模型并行 PP ① 将模型的不同…

cursor机器码重置

1、下载vscode插件 cursor-fake-machine-0.0.2 2、将插件拖入拓展 3、彻底将cursor账号退出 setting -> Manage -> 退出账号 4、打开cursor&#xff0c;ctrlshiftp &#xff0c;输入fake,点击确定

全国产FMC子卡-16bit 8通道2.4G

国产化FMC DA子卡&#xff0c;16bit 8通道2.4GS/s 全国产FMC子卡是一款高分辨率、高采样率的全国产多通道标准双宽DAC FMC子板。其接口电气和结构设计均依据FMC标准(ANSI/VITA 57.1)&#xff0c;通过两个高密度FMC连接器&#xff08;HPC&#xff09;连接至FPGA载板。它提供8路A…

fpga:分秒计时器

任务目标 分秒计数器核心功能&#xff1a;实现从00:00到59:59的循环计数&#xff0c;通过四个七段数码管显示分钟和秒。 复位功能&#xff1a;支持硬件复位&#xff0c;将计数器归零并显示00:00。 启动/暂停控制&#xff1a;通过按键控制计时的启动和暂停。 消抖处理&#…

小白 thingsboard 拆分前后端分离

1、modules 里注释掉ui_ugx <modules><module>netty-mqtt</module><module>common</module><module>rule-engine</module><module>dao</module><module>edqs</module><module>transport</module&g…