go GC(垃圾回收)

目录

    • 什么是GC
    • go语言中的GC
      • 标记清除法
      • 三色标记法
        • 两种不变式
      • go对上述规则的两种实现机制:
        • 插入写屏障
        • 删除写屏障
      • 混合写屏障法
    • 总结

什么是GC

GC
堆内存上分配的数据对象,不会再使用时,不会自动释放内存,就变成垃圾,在程序的运行过程中,如果不能及时清理,会导致越来越多的内存空间被浪费,导致系统性能下降。

因此需要内存回收,内存回收分为两种方式

1.手动释放占用的内存空间

可能会出现的问题:
悬挂指针: 释放的早了,后续对数据的访问就会出错,因为对应的内存空间可能已经清空,重新分配,甚至是归还给操作系统了。
内存泄漏: 如果忘了释放,一直占用内存,导致内存泄漏。

2.自动内存回收

开发人员无需手动管理释放已经分配但是没有引用的对象内存,而由程序自动检测对象决定是否要回收其内存。

系统如何检测哪些应该是被回收的数据对象呢?
**核心思想:**程序中用得到的数据,一定是可以从栈或数据段这些根节点追踪得到的数据,追踪不到的数据,肯定用不到,也就是垃圾。

go语言中的GC

go语言GC机制经过多年的迭代最终性能良好。

一个概念:
STW:stop the word,指程序执行过程中,中断暂停程序逻辑,专门去进行垃圾回收。

标记清除法

把根数据段上的数据作为root,基于他们进行进一步的追踪,追踪到的数据就进行标记,最后把没有标记的对象当作垃圾进行释放。

  • 开启STW,
  • 从根节点出发,标记所有可达对象
  • 停止STW,然后回收所有未标记的对象。

三色标记法

白灰黑

  • 初始时,所有对象都为白色,
  • GC开始,开启SWT,遍历堆栈root,将直接可达的对象标记为灰色,
  • 遍历灰色结点,将直接可达的对象标记为灰色,自身标记为黑色,
  • 继续执行第三步同样的步骤,直到所有能够访问到的结点都被标记为黑色,
  • 关闭SWT,回收所有白色标记的对象。

如果没有SWT,程序正常执行,可能会有如下的情况,导致对象被误当作垃圾回收。
白色对象本来被一个灰色对象引用,但是该灰色对象将该引用赋给了黑色对象,灰对白的引用断开。此时,由于不会对黑色对象的引用进行检测标记,即该白色节点即使被引用也无法被标记为灰色,最终当作垃圾处理掉。

三色标记法出现对象丢失,要满足以下两个条件:

  • 条件一:白色对象被黑色对象引用
  • 条件二:灰色对象与白色对象之间的可达关系遭到破坏

只要破坏两个中的任何一个不会导致对象丢失的发生。

两种不变式

如何破坏两个条件

  • 强不变式: 不允许黑色对象引用白色对象
  • 弱不变式: 黑色对象可以引用白色对象,但是白色对象必须直接或间接被灰色对象引用。(保证白色对象一定会被扫描到)

go对上述规则的两种实现机制:

插入写屏障

当一个对象引用另外一个对象时,将另外一个对象标记为灰色。

插入屏障仅会在堆内存中生效,不对栈内存空间生效,这是因为go在并发运行时,大部分的操作都发生在栈上,函数调用会非常频繁。数十万goroutine的栈都进行屏障保护自然会有性能问题。

如果一个栈对象 黑色引用白色对象,白色对象依然会被当作垃圾回收。
因此,最后还需要对栈内存 进行STW,重新rescan,确保所有引用的被引用的栈对象都不会被回收。

删除写屏障

当一个白色对象被另外一个对象时解除引用时,将该被引用对象标记为灰色(白色对象被保护

缺点:产生内存冗余,如果上述该白色对象没有被别的对象引用,相当于还是垃圾,但是这一轮垃圾回收并没有处理掉他。

混合写屏障法

  • GC刚开始的时候,会将栈上的可达对象全部标记为黑色。

  • GC期间,任何在栈上新创建的对象,均为黑色。
    将栈上的可达对象全部标黑,最后无需对栈进行STW,就可以保证栈上的对象不会丢失

  • 堆上被删除的对象标记为灰色

  • 堆上新添加的对象标记为灰色

总结

go 1.3 之前采用标记清除法,需要STW
go 1.5 采用三色标记法,插入写屏障机制(只在堆内存中生效),最后仍需对栈内存进行STW
go 1.8 采用混合写屏障机制,屏障限制只在堆内存中生效。避免了最后节点对栈进行STW的问题,提升了GC效率

你可能感兴趣的:(Go,go)