Golang中GC和三色屏障机制【Golang面试必考】

news2025/7/31 4:40:25

文章目录

    • Go v1.3 标记—清楚(mark and sweep)方法
    • Go V1.5 三色标记法
    • 三色标记过程无STW的问题
    • 强弱三色不变式
    • 插入写屏障
    • Go V1.8的三色标记法+混合写屏障机制
    • 混合写屏障场景
      • 场景1:对象被一个堆对象删除引用,成为栈对象的下游
      • 场景2:对象被一个栈对象删除引用,成为另一个新建栈对象的下游
      • 场景3:对象被一个堆对象删除引用,成为另一个堆对象的下游
      • 场景4:对象从一个栈对象删除引用,成为另一个堆对象的下游
    • 总结

Go v1.3 标记—清楚(mark and sweep)方法

  • 主要流程

    • 暂停程序业务逻辑,找出可达对象和不可达对象;
    • 开始标记,程序找出它所有可达的对象,并做上标记;
    • 标记完了之后,然后开始清除未标记的对象;
    • 停止暂停,让程序继续跑,然后循环重复这个过程,直到process程序声明周期结束;
  • 标记清除整体逻辑

在这里插入图片描述

  • 标记清除的缺点

    • STW,stop the world ;让程序暂停,程序出现卡顿
    • 标记需要扫描整个heap;
    • 清楚数据会产生heap碎片;【如果地址不连续】

    其中最大的问题还是因为STW太费时间,早期的探索是通过将sweep阶段移到STW之外,这确实是一种改善的方法,但是始终难以改变这种低级效能。所以需要尝试采用新的标记模式来代替清楚标记法(mark-sweep)—三色标记法。

在这里插入图片描述

Go V1.5 三色标记法

  • 主要流程

在这里插入图片描述

在这里插入图片描述

主要的流程如下【广度优先搜索】:

  • 只要是新创建的对象,默认的颜色都是标记为"白色";
  • 每次GC回收开始,然后从根节点开始遍历所有对象,把遍历到的对象从白色集合中放入"灰色"集合中;
  • 遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将原先的灰色对象放入黑色集合当中;
  • 重复第三步,直到灰色中无任何对象;
  • 回收所有白色标记表的对象,也就是回收垃圾;

三色标记过程无STW的问题

  • 如果三色标记中不启动STW会怎么样?

在这里插入图片描述

简单来说,就是没有STW,那么如果对象2对对象3依赖的指针取消了,而对象四新建了一个对对象3的依赖,那么按照之前的原则,每次都是对灰色节点进行遍历,所以这个时候,无法将对象3标记为灰色,故会造成错误。

  • 三色标记最不希望发生的事情

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

    以上两个条件同时满足就会发生对象的丢失。因此有必要使用STW,但是应当尽可能的提高GC效率,减少STW时间。

在这里插入图片描述

强弱三色不变式

  • 强三色不变式

    强制性的不允许黑色对象引用白色对象。

  • 弱三色不变式

    黑色对象可以引用白色对象,但是白色对象存在其他灰色对象对它的引用,或者可达它的链路上游存在灰色对象。

在三色标记中如果满足强/弱之一,即可保证对象不丢失。为了使用上面这种思想,引入了屏障

插入写屏障

  • 屏障的理解
    在这里插入图片描述

  • 屏障机制

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

      在A对象引用B对象的时候,B对象被标记为灰色(将B挂在A下游,B必须被标记为灰色)【强三色不变式】

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

      ⭐️⭐️⭐️一般为了保证效率,不会在栈上使用插入屏障。【栈不触发插入屏障,是因为栈上的内存会随着栈销毁而回收,除非触发内存逃逸】

在这里插入图片描述

也就是说在堆上的对象才会启用插入屏障。在准备回收白色前,重新遍历扫描一边栈空间,此时加STW暂停保护栈,防止有外界干扰(有新的白色被黑色添加)

在这里插入图片描述

插入写屏障的不足就是在结束时需要用STW来重新扫描栈,大约需要10ms~100ms
  • 删除屏障:当引用关系被删除的时候触发的机制

    具体操作:被删除的对象,如果自身或者上游对象为灰色或者白色,那么被标记为灰色【满足弱三色不变式,保护灰色对象到白色对象的路径不会断】

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

    删除写屏障的不足之处在于回收精度低,一个对象及时被删除了最后一个指向它的指针也依旧可以活过这一轮,在下一轮GC中被清理掉。

Go V1.8的三色标记法+混合写屏障机制

  • 具体操作

    • GC开始将栈上的对象全部扫描并标记为黑色(之后不在进行第二次重复扫描,无需STW)
    • GC期间,任何在栈上创建的新对象,均为黑色
    • 被删除的对象标记为灰色
    • 被添加的对象标记为灰色

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

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

混合写屏障场景

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

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

对象4删除了对象7的引用关系,因为对象4是堆区,所以触发删除屏障,标记被删除的对象7为灰。【注意这个地方不能认为栈里面元素添加一个就直接标记为黑色,因为栈的区域不启用屏障】

场景2:对象被一个栈对象删除引用,成为另一个新建栈对象的下游

(1)、新创建一个对象9在栈上(因为是混合写屏障模式中,GC过程汇总任何在栈中新创建的对象均标记为黑色)

(2)、对象9添加下游引用栈堆对象3(直接添加,栈不启动屏障,无屏障效果)

(3)、对象2删除对象3的引用关系(直接删除,栈不启动写屏障,无屏障效果)

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

//伪代码
堆对象10 -> 对象7 = 堆对象7; // 将堆对象7 挂在 堆对象10 下游
堆对象4 -> 对象7 = null; // 对象4 删除引用 对象7

(1)、堆对象10已经扫描标记为黑(黑色情况比较特殊,其他颜色暂不考虑)。

(2)、堆对象10添加下游引用堆对象7,触发屏障机制,被添加的对象标记为灰色,对象7变成灰色(对象6被保护)。

(3)、堆对象删除下游引用堆对象7,触发屏障机制,被删除的对象标记为灰色,对象7被标记为灰色。

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

// 伪代码
栈对象1 -> 对象2 = null; // 对象1 删除引用 对象2
栈对象4 -> 对象2 = 栈对象2 // 对象4 添加栈对象2
堆对象 -> 对象7 = null; // 对象4 删除一个对象7

(1)、栈对象1删除对堆对象2的引用。(栈空间不触发写屏障)。

(2)、堆对象将之前引用对象7的关系,转移至对象2(对象4删除对象7的引用关系)。

(3)、对象4在删除的时候,触发写屏障,标记被删除对象7为灰色。保护对象7及其下游节点。

总结

Go V1.3 使用普通标记清除法,整体过程需要STW,效率极其低

Go V1.5 三色标记法,堆空间启动写屏障,栈空间不启动,全部扫描一次后,需要重新扫描一次栈(需要STW),效率极其普通

Go V1.8 三色标记法+混合写屏障机制,堆空间启动,栈空间不启动,整体过程几乎不需要STW,效率较高

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

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

相关文章

PyQt 做美*女GIF设置桌面,每天都很爱~

人生苦短,我用python 要说程序员工作的最大压力不是来自于工作本身, 而是来自于需要不断学习才能更好地完成工作, 因为程序员工作中面对的编程语言是在不断更新的, 同时还要学习熟悉其他语言来提升竞争力… 好了,学习…

python模块引入问题和解决方案_真方案不骗人

1.pycharm运行python脚本的过程 使用pycharm等编辑器run/debug运行python脚本时,编辑器会通过本地python命令全路径执行脚本,例如 D:\DevelopTools\Python\python.exe D:/Codes/一长串路径/bbss_nature_python/demo/test_no_param_in.py 并且会在pyth…

自动化框架如何搭建?让10年阿里自动化测试老司机帮你搞定!自动化测试脚本怎么写?

一、何为框架?何为自动化测试框架? 无论是日常技术交流,还是在自动化测试实践中,经常会听到一个词叫:框架。之前对“框架”这个词知其然不知其所以然。现在看过一些资料以及加上我自己的一些实践有了我自己的一些看法…

PowerJob中的Vert.x的应用,是点睛之笔还是大材小用?我感觉有点故意炫技啊

这是一篇为了参加活动写得文章,不知道为什么,写得时候网络巨差,我是顶着闹心发上来的,最后大家女神节快乐。 最近难得忙了一下,领导让我从Vert.x和lagom中技术选型,因为lagom是scala写得,我虽然…

2023高质量设计竞赛汇总,想证明自己实力的快来

对于设计师来说,参加设计比赛不仅能够提升自己的设计能力,也是一条证明实力最好的捷径。小编也收集整理了不少近期设计大赛,分别标注了截止日期和官网等,宝子们记得码住收藏,赶紧SHOW起来!优酷X站酷 一千零…

湖南媒体资源有哪些?湖南媒体邀约怎么做?

传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 湖南位于中国中南部,以其美丽的自然风光、丰富的历史文化和独特的湖湘文化而著名,拥有丰富的媒体资源。以下是一些湖南省的媒体资源: 1.湖南日报社: …

Spark 应用调优

Spark 应用调优人数统计优化摇号次数分布优化Shuffle 常规优化数据分区合并加 Cache优化中签率的变化趋势中签率局部洞察优化倍率分析优化表信息 : apply : 申请者 : 事实表lucky : 中签者表 : 维度表两张表的 Schema ( batchNum,carNum ) : ( 摇号批次&#xff0c…

Java基础——Lambda表达式

一、函数式编程思想概述https://www.runoob.com/java/java8-lambda-expressions.html在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿数据做操作”面向对象强调“必须通过对象的形式来做事情”,做事情之前首先要创建一个对象函数…

B站游戏推广,怎样查看B站游戏推广榜数据?

近年来,B站发展得越来越大,越来越多的游戏商也加入B站进行推广,那么作为游戏运营商,怎样查看游戏在B站上的推广数据呢?游戏排行榜游戏商业推广榜包含视频推广榜、直播推广榜,按照日榜、周榜、月榜&#xff…

【Linux 网络编程1】使用UDP/TCP编写套接字,多进程/多线程版本的TCP编写的套接字,将套接字封装

目录 1.学习网络编程前的一些基础知识 2.UDP(user datagram protocol)协议的特点 3.使用有UPD编写套接字 4.使用TCP编写套接字 4.2.TCP客服端 4.3.TCP服务器端 4.4.单进程版本(没有人会使用) 4.5.多进程版本 4.6.多线程版本 5.把套接字封装 1…

扬帆优配|2600亿新能源巨头狂飙!外资唱多中国:再涨15%

全国停摆的危机,正在迫临法国。 大停工正在将法国推向风险境地。法国政府估计,当地时间3月7日,将迸发全国大型停工游行。法国总工会宣告,到时将让全法国停摆。法国担任交通业务的部长级代表克莱蒙博讷正告称,7日将成为…

JavaScript 混淆技术

根据JShaman(JShaman是专业的JavaScript代码混淆加密网站)提供的消息,JavaScript混淆技术大体有以下几种: 变量混淆 将带有JS代码的变量名、方法名、常量名随机变为无意义的类乱码字符串,降低代码可读性,如…

原神 Android 教程 —安卓版

准备材料 一台能读写 /system 分区的 Android 手机(或:一台安装了 Magisk 的 Android 手机) 有人搞出来免root端了,此条件不再必须私服客户端

数据同步工具Sqoop

大数据Hadoop之——数据同步工具SqoopSqoop基本原理及常用方法 1 概述 Apache Sqoop(SQL-to-Hadoop)项目旨在协助RDBMS(Relational Database Management System:关系型数据库管理系统)与Hadoop之间进行高效的大数据交…

HStream Console、HStreamDB 0.14 发布

近两个月,HStreamDB 相继发布了 0.13 和 0.14 版本,包含多项已知问题修复。同时,我们也发布了全新的 HStream Console 组件,为 HStreamDB 带来了简洁友好的图形化管理界面,将帮助用户更轻松地使用和管理 HStreamDB. H…

LinqConnect兼容性并支持Visual Studio 2022版本

LinqConnect兼容性并支持Visual Studio 2022版本 现在支持Microsoft Visual Studio 2022版本17.5预览版。 添加了Microsoft.NET 7兼容性。 共享代码-共享相同的代码,以便在不同的平台上处理数据。LinqConnect是一种数据库连接解决方案,适用于不同的基于.…

Ubuntu下安装Docker

大家好,我是中国码农摘星人。 欢迎分享/收藏/赞/在看! 文章目录1 安装Docker1.1 使用官方安装脚本自动安装 (仅适用于公网环境)1.2 手动安装帮助1.2.1 Ubuntu 14.04 16.04 (使用apt-get进行安装)2 安装校验3 镜像加速器3.1 安装&a…

在 k8S 中搭建 SonarQube 7.4.9 版本(使用 PostgreSQL 数据库)

本文搭建的 SonarQube 版本是 7.4.9-community,由于在官方文档中声明 7.9 版本之后就不再支持使用 MySQL 数据库。所以此次搭建使用的数据库是 PostgreSQL 11.4 版本。 一、部署 PostgreSQL 服务 1. 创建命名空间 将 PostgreSQL 和 SonarQube 放在同一个命名空间…

Docker(二)

5.容器数据卷 1.什么是容器数据卷 docker理念回顾 将应用和环境打包成一个镜像! 数据?如果数据都在容器中,那么我们容器删除,数据就会丢失!需求:数据可以持久化 MySQL,容器删了&#xff0c…

都工作3年了,怎么能不懂双亲委派呢?(带你手把手断点源码)

💗推荐阅读文章💗 🌸JavaSE系列🌸👉1️⃣《JavaSE系列教程》🌺MySQL系列🌺👉2️⃣《MySQL系列教程》🍀JavaWeb系列🍀👉3️⃣《JavaWeb系列教程》…