Golang垃圾回收(GC) 底层原理 2024-01-28 默认分类 暂无评论 491 次阅读 参考链接: [Golang垃圾回收(GC)介绍 ](https://liangyaopei.github.io/2021/01/02/golang-gc-intro/ "Golang垃圾回收(GC)介绍") [刘丹冰Aceld Golang中GC回收机制三色标记与混合写屏障](https://www.bilibili.com/video/BV1wz4y1y7Kd?p=14&vd_source=f1a7951aa84af4793b91a3e046fcd901) GC机制 (garbage collection) STW (stop the world) 三色标记 可以理解为标记法的改良版 将对象分为三个颜色 白色: 未标记待回收 灰色: 子对象未标记, 待检查 黑色: 已标记, 不回收 标记过程如下 (1)起初所有的对象都是白色的; (2)从根对象出发扫描所有可达对象,标记为灰色,放入待处理队列; (3)从待处理队列中取出灰色对象,将其引用的对象标记为灰色并放入待处理队列中,自身标记为黑色; (4)重复步骤(3),直到待处理队列为空,此时白色对象即为不可达的“垃圾”,回收白色对象; ![](https://i-cooltea.top/usr/uploads/2024/01/2845289671.png) 写屏障 **STW** (Stop The World的缩写),或者是Start The World的缩写。 通常意义上指的是从Stop The World到Start The World这一段时间间隔。垃圾回收过程中为了保证准确性、防止无止境的内存增长等问题而不可避免的需要停止赋值器进一步操作对象图以完成垃圾回收。STW时间越长,对用户代码造成的影响越大。 GC的写屏障机制是为了处理并发环境下的垃圾收集问题而设计的。 写屏障(Write Barrier)是指在程序中进行内存写操作时,会触发额外的操作,用于辅助垃圾收集器进行内存管理。写屏障的主要作用包括以下几点: 1. 协助垃圾收集器识别指针:在写入指针类型的数据时,写屏障会记录这个写操作,以便垃圾收集器能够追踪对象之间的引用关系。这有助于垃圾收集器准确地识别哪些对象是可达的,哪些对象可以被回收。 2. 协助垃圾收集器进行并发标记:在并发标记阶段,写屏障会协助标记阶段的并发进行,确保在并发标记的同时,能够准确地记录写操作的影响,以维护正确的内存对象状态。 3. 优化垃圾收集器的效率:通过写屏障机制,垃圾收集器能够更精确地跟踪对象之间的引用关系,同时在并发情况下也能够更高效地进行垃圾收集操作。 总的来说,写屏障机制在Go语言的GC中起着至关重要的作用,它通过记录内存写操作,帮助垃圾收集器准确地追踪对象之间的引用关系,同时也为并发环境下的垃圾收集提供了支持。这有助于提高垃圾收集器的效率和准确性,从而更好地管理程序的内存。 为什么称之为屏障 ? 混合写屏障是 Go 语言中垃圾回收器的一种实现技术,它用于在并发执行时保证对共享数据的线程安全访问。其名称来源于操作系统中的「屏障」概念,屏障是一种同步机制用于达到某个同步状态。混合写屏障在垃圾回收的上下文中通过插入写屏障指令来保证共享数据的写入操作不被回收。这个技术结合了并发执行和写屏障机制,确保了并发环境下垃圾回收的内存安全和正确性。 gov1.3的GC (简单的标记清除) 启动STW > 标记可达 > 剩余的不可达对象即为待清除对象 > 停止STW 缺点: 1. STW会出现卡顿 2. 需扫描整个堆 3.需heap碎片 gov1.5的GC (三色标记清除) 所有节点默认颜色为白色 代表未被引用 将所有遍历到的标记为灰色 ( 子节点未扫描 ) 对于灰色结点的子元素全部扫描结束 则将其标记为黑色 扫描结束后所有未被标记的白色对象即为待回收的对象 ![](https://i-cooltea.top/usr/uploads/2024/03/421058838.png) ![](https://i-cooltea.top/usr/uploads/2024/03/4141578826.png) 三色标记的问题 当黑色引用白色 且原有的灰色引用也被删除 将导致清理发生错误 (下图的对象3被4引用 不应该被删除) ![](https://i-cooltea.top/usr/uploads/2024/03/1936362723.png) ![](https://i-cooltea.top/usr/uploads/2024/03/780687486.png) 通过STW过程有明显的资源浪费 对所有的用户程序都有很大影响 如何保证对象不丢失, GC尽可能高效? ![](https://i-cooltea.top/usr/uploads/2024/03/2823203500.png) 插入屏障: 堆对象被引用时将其标记为灰色 (栈空间会在清除前进行一次STW重新扫描 大约10~100ms) 删除屏障: 若被解除引用的对象非黑色则标记为灰色 缺点: 存在延迟删除的情况 gov1.8的GC (三色标记 + 混合写屏障) 1. GC开始将栈上对象全部标记为黑色 2. GC期间 任何栈上创建的新对象 均为黑色 3. 被删除的对象标记为灰色 4. 被添加的对象标记为灰色 满足: 变形的若三色不变式 ( 结合了插入,删除写屏障的优点) 场景1 堆对象变成栈对象的下游 => 触发删除屏障 (解除 4->7 ) ( 由于是堆上的操作, 触发屏障机制, 将结点标记为灰色) ![](https://i-cooltea.top/usr/uploads/2024/03/295051475.png) 场景2 对象被一个栈对象删除引用, 成为另一个栈对象下游 => 解除 2->3 , 新增 9->3 由于是栈上的操作 (直接删除对象3的引用, 不触发屏障机制) ![](https://i-cooltea.top/usr/uploads/2024/03/582924768.png) 场景3 堆对象 被转义引用 到另一个堆对象 => 解除 4->7 ( 由于是对象4在堆上, 触发屏障机制, 将结点标记为灰色) ![](https://i-cooltea.top/usr/uploads/2024/03/1186383012.png) 场景4 栈对象引用 变成 堆对象引用 => 解除 1->2 和 4->7 , 新增 4->2, (由于对象4在堆上,触发屏障机制, 将结点标记7为灰色 对象7将延迟回收) ![](https://i-cooltea.top/usr/uploads/2024/03/2334078597.png) ![](https://i-cooltea.top/usr/uploads/2024/03/1120172003.png) 总结 总的来说,Go 1.8 版本的 GC 带来了并发标记和较低的暂停时间,显著提高了程序的吞吐量和响应性能。这些优化措施使得 Go 1.8 版本的 GC 在大多数情况下能够以低延迟和高效率进行垃圾回收,从而更适合构建高性能、低延迟的应用程序。 GO 1.8 以上使用三色标记 + 写屏障 机制 文章目录 三色标记 写屏障 为什么称之为屏障 ? gov1.3的GC (简单的标记清除) gov1.5的GC (三色标记清除) 三色标记的问题 如何保证对象不丢失, GC尽可能高效? gov1.8的GC (三色标记 + 混合写屏障) 场景1 堆对象变成栈对象的下游 场景2 对象被一个栈对象删除引用, 成为另一个栈对象下游 场景3 堆对象 被转义引用 到另一个堆对象 场景4 栈对象引用 变成 堆对象引用 标签: golang 转载请注明文章来源 本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
评论已关闭