详解Golang的GC三色标记法

 更新时间:2023年05月16日 09:54:33   作者:wangxiaoangg  
这篇文章主要为大家介绍了Golang的GC三色标记法,文中有详细的实现过程供大家参考,对大家的学习或工作有一定帮助,感兴趣的可以跟着小编一来看看

一 概念基础

1.1三色标记法将对象分为三类

把图过程中遇到的对象,按“是否访问过”这个条件标记成以下三种颜色:

白色对象(可能死亡):未被回收器访问到的对象。在回收开始阶段,所有对象均为白色,当回收结束后,白色对象均不可达。

灰色对象(波面):已被回收器访问到的对象,但回收器需要对其中的一个或多个指针进行扫描,因为他们可能还指向白色对象。

黑色对象(确定存活):已被回收器访问到的对象,其中所有字段都已被扫描,黑色对象中任何一个指针都不可能直接指向白色对象。

1.2 标记过程

  • 起初所有的对象都是白色的;
  • 从根对象出发扫描所有可达对象,标记为灰色,放入待处理队列;
  • 从待处理队列中取出灰色对象,将其引用的对象标记为灰色并放入待处理队列中,自身标记为黑色;
  • 重复步骤3,直到待处理队列为空,此时白色对象即为不可达的“垃圾”,回收白色对象;
  • 回收所有的白色对象,也就是回收垃圾

根对象

在垃圾回收的术语中又叫做根集合,它是垃圾回收器在标记过程时最先检查的对象。

  • 全局变量:程序在编译期就能确定的那些存在于程序整个生命周期的变量。
  • 执行栈:每个 goroutine 都包含自己的执行栈,这些执行栈上包含栈上的变量及指向分配的堆内存区块的指针。
  • 寄存器:寄存器的值可能表示一个指针,参与计算的这些指针可能指向某些赋值器分配的堆内存区块。

1.3 STW

STW(Stop The World)机制是指在进行垃圾回收时,会暂停应用程序的运行,以便进行垃圾回收操作。这意味着在进行垃圾回收时,应用程序将无法继续执行。

为什么需要STW

STW(Stop-The-World)机制来确保并发操作的正确性。

如果不设置STW机制,那么在进行GC时,应用程序线程可能会继续执行,从而导致内存管理的不一致性和错误。此外,GC可能会导致内存分配和释放的不连续,从而导致内存碎片化问题。

因此,需要STW机制来确保GC的正确性和内存管理的一致性。虽然STW机制会导致一定的性能损失,但是这是必要的代价,以确保应用程序的正确性和稳定性。

1.4 屏障机制

1.4.1强、弱三色不变式

强三色不变式:强制性的不允许黑色对象引用白色对象,只能引用灰色对象,这样就不会出现白色对象被误删的情况。

弱三色不等式 :
保护灰色对象到白色对象的路径不会断;

黑色对象可以引用白色对象,白色对象存在其他灰色对象对它的引用。
或可达它的链路上游存在灰色对象。这样实则是黑色对象引用白色对象,白色对象处于一个被删除的状态,但是上游灰色对象的引用,可以保护白色对象,使其安全。

为了遵循上述两种方式,GC算法演进到两种屏障方式,“插入屏障”和“删除屏障”。

1.4.2 插入屏障

在A对象引用B对象时,B对象被标记为灰色。(将B挂在A下游,B必须被标记为灰色)

满足强三色不等式。

插入屏障机制在栈空间的对象操作不使用,仅仅使用在堆空间对象的操作中。

1.4.3 删除屏障

被删除的对象,如果本身为灰色或白色,那么标记为灰色。

满足弱三色不等式。

1.4.4 混合屏障

插入写屏障和删除写屏障的缺点:

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

Go1.8引入混合写屏障机制,避免了对栈的重复扫描过程,极大减少了STW的时间。

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

二 GC过程

2.1 阶段1:Mark Setup 标记准备

为了打开写屏障,必须停止每个goroutine,让垃圾收集器观察并等待每个goroutine进行函数调用,等待函数调用是为了保证goroutine停止时处于安全点。(期间会STW)

2.2 阶段2:Marking 标记

一旦写屏障打开,垃圾收集器就开始标记阶段。

标记阶段需要标记在堆内存中仍然在使用中的值。首先检查所有现goroutine的堆栈,以找到堆内存的根指针。然后收集器必须从那些根指针遍历堆内存图,标记可以回收的内存。

当存在新的内存分配时,会暂停分配内存过快的那些 goroutine,并将其转去执行一些辅助标记(Mark Assist)的工作,从而达到放缓继续分配、辅助 GC 的标记工作的目的。

2.3阶段3:Mark Termination 标记结束

这个阶段会关闭掉阶段1开启的屏障,并计算下一次清理的目标和计划。(本阶段会STW)

2.4 阶段4:Sweeping 清理

清理阶段用于回收标记阶段中标记出来的可回收内存。当应用程序goroutine尝试在堆内存中分配新内存时,会触发该操作,清理导致的延迟和吞吐量降低被分散到每次内存分配时。

本阶段会并发执行,清除前面标记出来需清理的内存。

以上就是详解Golang的GC三色标记法的详细内容,更多关于Golang GC 三色标记法的资料请关注脚本之家其它相关文章!

相关文章

  • goland -sync/atomic原子操作小结

    goland -sync/atomic原子操作小结

    这篇文章主要介绍了goland -sync/atomic原子操作,原子操作能够保证执行期间是连续且不会被中断(变量不会被其他修改,mutex可能存在被其他修改的情况),本文给大家介绍的非常详细,需要的朋友参考下
    2022-08-08
  • Go可变参数函数的实现

    Go可变参数函数的实现

    可变参数函数是指函数参数的某个参数可有可无,即这个参数的个数可以为0会多个,可变参数函数参数在日常编程中大量使用,本文主要介绍了Go可变参数函数的实现,感兴趣的可以了解一下
    2023-12-12
  • Go设计模式之迭代器模式讲解和代码示例

    Go设计模式之迭代器模式讲解和代码示例

    迭代器是一种行为设计模式, 让你能在不暴露复杂数据结构内部细节的情况下遍历其中所有的元素,本文将为大家详细介绍Go 迭代器模式,文中详细的代码示例,需要的朋友可以参考下
    2023-07-07
  • Go语言基础go install命令使用示例详解

    Go语言基础go install命令使用示例详解

    这篇文章主要为大家介绍了Go语言基础go install命令的使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2021-11-11
  • GoLang之使用Context控制请求超时的实现

    GoLang之使用Context控制请求超时的实现

    这篇文章主要介绍了GoLang之使用Context控制请求超时的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • Golang 关于Gin框架请求参数的获取方法

    Golang 关于Gin框架请求参数的获取方法

    Gin是Go语言的Web框架,提供路由和中间件支持,本文介绍如何使用Gin获取HTTP请求参数,包括URLPath参数、URLQuery参数、HTTPBody参数和Header参数,详解直接获取和绑定到结构体两种方法,帮助开发者高效处理Web请求
    2024-10-10
  • Go语言LeetCode题解706设计哈希映射

    Go语言LeetCode题解706设计哈希映射

    这篇文章主要为大家介绍了Go语言LeetCode题解706设计哈希映射示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Golang内存管理之垃圾收集器详解

    Golang内存管理之垃圾收集器详解

    这篇文章我们主要介绍垃圾收集器的设计原理以及Golang垃圾收集器的实现原理,文中有详细的代码示例及图文介绍,感兴趣的小伙伴跟着小编一起来学习吧
    2023-06-06
  • go性能分析工具pprof的用途及使用详解

    go性能分析工具pprof的用途及使用详解

    刚开始接触go就遇到了一个内存问题,在进行内存分析的时候发现了一下比较好的工具,在此留下记录,下面这篇文章主要给大家介绍了关于go性能分析工具pprof的用途及使用的相关资料,需要的朋友可以参考下
    2023-01-01
  • 基于Go+WebSocket实现实时通信功能

    基于Go+WebSocket实现实时通信功能

    在互联网应用程序中,实时通信是一种非常重要的功能,WebSocket 是一种基于 TCP 的协议,它允许客户端和服务器之间进行双向通信,本文将介绍如何使用 Golang 创建单独的 WebSocket 会话,以实现实时通信功能,需要的朋友可以参考下
    2023-10-10

最新评论