golang 的 gc垃圾回收机制

文章目录

  • 一、常见的垃圾回收算法?
    • 1.1 引用计数法
    • 1.2 分代收集
    • 1.3 三色标记法
  • 二、三色标记步骤
    • 2.1初始化图例
    • 2.2 GC开始,遍历root,将直接可达的标记为灰色图例
    • 2.3 遍历灰色列表,将直接可达的标记为灰色,自身标记为黑色
    • 2.4 重复上述步骤,直到标记完所有对象
    • 2.5 将标记为白色的对象进行垃圾回收(GC完成)
  • 三、混合写屏障机制
  • 四、完整的gc流程
  • 五、gc执行的时机,什么时候触发gc
  • 总结

一、常见的垃圾回收算法?

1.1 引用计数法

  • 介绍:每个对象维护一个引用计数,记录对象呗应用的次数,每当一个对象被引用时,引用计数就会增加,当对象不背引用时,引用计数就会减少,如果对象计数变为0,那么可以对该对象进行垃圾回收。
  • 代表:python,php
  • 优缺点:
    • 优点:实现简单,处理快
    • 缺点:无法处理循环引用,两个对象相互引用,永远无法清除

1.2 分代收集

  • 按照对象的生命周期长短划分不同的代空间,生命周期长的放入老年代,短的放入新生代,不同代的对象有不同的回收算法和频率
  • 代表:java
  • 优缺点:
    • 优点:性能好
    • 缺点:需要STW(stop the world),算法复杂

1.3 三色标记法

  • 介绍:从根节点开始遍历所有引用对象,标记引用的对象为不同的颜色,被标记为白色的对象进行回收
  • 代表:golang
  • 优缺点:
    • 优点:解决了计数器的缺点
    • 缺点:需要stw,暂时停掉程序的运行

golang的gc算法使用三色标记法+混合写屏障 尽量减少STW的时间

二、三色标记步骤

  1. 初始化,所有对象标记为白色
  2. gc开始,遍历root根节点,将引用对象的对象标记为灰色,存入灰色列表
  3. 遍历灰色列表,将直接可达的对象标记为灰色,自身标记为黑色
  4. 重复上述步骤,直到标记完所有对象(灰色列表为空)
  5. 将白色对象删除,保留黑色对象

2.1初始化图例

2.2 GC开始,遍历root,将直接可达的标记为灰色图例

2.3 遍历灰色列表,将直接可达的标记为灰色,自身标记为黑色

2.4 重复上述步骤,直到标记完所有对象

2.5 将标记为白色的对象进行垃圾回收(GC完成)

三、混合写屏障机制

在三色标记期间,如果没有进行STW(stop the world) ,并发创建对象or删除对象,可能 存在垃圾对象或误删对象的情况:

  • 场景1:如果没有stw保护机制,黑色对象的引用对象被删除,当前黑色对象不可达,正常情况当前对象应该被删除,但是gc期间只会循环灰色队列,不会循环黑色队列,因此该对象为垃圾对象,但是被标记黑色,不可回收
  • 场景2:黑色对象引用了白色对象,白色对象有了引用对象应该被保护,但是仍然会被回收(被灰色对象引用的白色对象,才会在下次进行判断是否可达,如果黑色对象引用白色对象,则不会处理)

所以在此处,go引入了 混合写屏障机制,满足以下条件:

  • 若三色不变式:黑色对象不允许引用白色对象;因为一旦被引用,该黑色对象将不继续参与gc,白色对象会被清除
  • 若三色不变式:黑色对象可以引用白色对象,但是该白色对象必须被其他灰色对象或者其上游有灰色对象引用,否则该白色对象被清除

注意:插入屏障仅会对堆内存生效,栈内存不生效,这是因为go在并发运行时,大部分操作都发生在栈上,函数调度非常频繁,数十万计的goroutine在栈中运行,屏障保护自然会很影响性能
所以在gc期间,任何在栈上创建的对象,均为黑色

四、完整的gc流程

  1. 准备阶段(mark setup):开启混合写屏障(write barrier)需要STW(stop the world )
  2. 标记开始(marking):使用三色标记法,与用户程序并发执行
  3. 终止标记(mark termination):对触发写屏障的对象进行重新扫描标记,关闭写屏障(write barrier) 需要STW(stop the world)
  4. 清理(sweeping): 将需要回收的内存还到堆中,将过多的内存归还给操作系统,与用户程序并发执行

五、gc执行的时机,什么时候触发gc

  • 定时触发:go运行时系统会根据一定的时间间隔进行垃圾回收,时间间隔根据程序内存的使用情况和性能需求进行自适应分配
  • 内存分配触发:当程序申请的内存超出一定阈值时,go运行时会触发垃圾回收机制,以防止过度使用内存
  • 栈伸缩触发:当goroutine的栈空间不足以容纳当前执行需求是,go运行时会触发垃圾回收机制来扩展栈空降
  • 主动调用:调用 runtime.GC
  • 空间不足触发:当线程的内存管理单元中不存在空闲空间时,创建32kb以下的对象可能出发垃圾回收,创建32kb以上的对象一定出发垃圾回收

总结

本文章主要介绍了golang中gc垃圾回收机制的运行原理,以及混合写屏障的机制
感谢观看

你可能感兴趣的:(golang,开发语言,后端)