当前位置: GO > gc垃圾回收

gc垃圾回收

2022-08-02 分类:GO 作者:admin 阅读(35)

业界常见的垃圾回收算法有以下几种:

  • 引用计数:对每个对象维护一个引用计数,当引用该对象的对象被销毁时,引用计数减1,当引用计数器为0时回收该对象。
    • 优点:对象可以很快地被回收,不会出现内存耗尽或达到某个阀值时才回收。
    • 缺点:不能很好地处理循环引用,而且实时维护引用计数,也有一定的代价。
    • 代表语言:Python、PHP、Swift
  • 标记-清除:从根变量开始遍历所有引用的对象,引用的对象标记为”被引用”,没有被标记的进行回收。
    • 优点:解决了引用计数的缺点。
    • 缺点:需要STW,即要暂时停掉程序运行。
    • 代表语言:Golang(其采用三色标记法)
  • 分代收集:按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,而短的放入新生代,不同代有不同的回收算法和回收频率。
    • 优点:回收性能好
    • 缺点:算法复杂
    • 代表语言: JAVA

循环引用问题:(对象之间互相引用,都不能回收)

在这里插入图片描述
上图为例,当代码执行完line7时,两个对象的引用计数均为2。此时将myObject1和myObject2分别置为null,以前一个对象为例,它的引用计数将减1。

若要满足垃圾回收的条件,需要清除myObject2中的ref这个引用,而要清除掉这个引用的前提条件是myObject2引用的对象被回收,可是该对象的引用计数也为1,因为myObject1.ref指向了它。以此类推,也就进入一种死循环的状态。


三色标记法:

前面介绍了对象标记状态的存储方式,还需要有一个标记队列来存放待标记的对象,可以简单想象成把对象从标记队列中取出,将对象的引用状态标记在span的gcmarkBits,把对象引用到的其他对象再放入队列中。

三色只是为了叙述上方便抽象出来的一种说法,实际上对象并没有颜色之分。这里的三色,对应了垃圾回收过程中对象的三种状态:

  • 灰色:对象还在标记队列中等待
  • 黑色:对象已被标记,gcmarkBits对应的位为1(该对象不会在本次GC中被清理)
  • 白色:对象未被标记,gcmarkBits对应的位为0(该对象将会在本次GC中被清理)

例如,当前内存中有A~F一共6个对象,根对象a,b本身为栈上分配的局部变量,根对象a、b分别引用了对象A、B, 而B对象又引用了对象D,则GC开始前各对象的状态如下图所示:

初始状态下所有对象都是白色的。

接着开始扫描根对象a、b:

由于根对象引用了对象A、B,那么A、B变为灰色对象,接下来就开始分析灰色对象,分析A时,A没有引用其他对象很快就转入黑色,B引用了D,则B转入黑色的同时还需要将D转为灰色,进行接下来的分析。如下图所示:

上图中灰色对象只有D,由于D没有引用其他对象,所以D转入黑色。直到没有灰色对象时,标记过程结束:

最终,黑色的对象会被保留下来,白色对象会被回收掉。

来源:https://www.topgoer.cn/docs/gozhuanjia/chapter044.2-garbage_collection


Go 三色标记算法的正确流程

1. 初始状态

  • 所有对象初始为白色(White)(未访问)。

  • 根对象(Root Set)(如全局变量、栈变量、寄存器变量)被标记为灰色(Grey)(待扫描)。

2. 标记阶段(Marking)

  1. 从灰色对象出发(而不是直接标记黑色):

    • 灰色代表“已发现但未扫描”的对象。

    • 从灰色对象开始,扫描它引用的所有子对象。

    • 每扫描一个灰色对象,就把它变成黑色(Black)(已扫描)。

    • 它引用的所有子对象(如果仍是白色)则变成灰色(待扫描)。

  2. 重复上述过程,直到没有灰色对象:

    • 此时,所有黑色对象存活的(从根可达)。

    • 所有白色对象不可达的,可以被回收。

3. 清除阶段(Sweeping)

  • 回收所有白色对象的内存。


Go 垃圾回收(GC)的触发时机

Go 的垃圾回收(GC)是 并发执行的,但它的运行时机由 运行时(runtime) 动态决定,主要取决于以下条件:


1. 核心触发条件

(1)内存分配阈值触发(主要方式)

  • Go 的 GC 是 基于内存分配量触发的,默认情况下:

    • 当 堆内存增长到上次 GC 后存活对象的 2 倍 时(由 GOGC 环境变量控制)。

    • 默认 GOGC=100(即堆增长 100% 触发 GC)。

    • 例如:

      • 上次 GC 后存活对象占 10MB,当堆增长到 20MB 时触发 GC。

  • 可通过 GOGC=off 完全禁用自动 GC(需手动调用 runtime.GC())。

(2)定时强制触发(2 分钟未触发时)

  • 如果 长时间未达到内存阈值(如程序内存使用很稳定),Go 会 每 2 分钟强制触发一次 GC,防止内存泄漏无法回收。

(3)手动触发

(4)系统内存不足时(Linux/Mac 的 sysmon 监控)

  • 如果系统剩余内存较少,Go 的 sysmon 监控线程会提前触发 GC 以释放内存。

「三年博客,如果觉得我的文章对您有用,请帮助本站成长」

赞(0) 打赏

支付宝
微信
0

支付宝
微信
标签:

上一篇:

下一篇:

你可能感兴趣

共有 0 - gc垃圾回收

博客简介

精彩评论

  • admin(6年前 (2020-03-09))

    分别用不同厚度的筏板定义,画图后这设置筏板变截面处理。 http://f.fwxgx.co...

    评:新文章!
  • admin(6年前 (2020-03-09))

    分别用不同厚度的筏板定义,画图后这设置筏板变截面处理。 http://f.fwxgx.co...

    评:新文章!
  • admin(6年前 (2020-03-09))

    新增一个框架图! http://biji.jinli.vip/wp-content/upl...

    评:新文章!
  • 一位WordPress评论者(6年前 (2020-02-13))

    嗨,这是一条评论。 要开始审核、编辑及删除评论,请访问仪表盘的“评论”页面。 评论者头像来自...

    评:世界,您好!