Golang入门——GC机制

时间:2024-10-10 09:58:43

Golang入门——GC机制

  • 常见GC算法
    • 引用计数
    • 标记清除
    • 分代收集
  • Go的GC
    • mark内存标记
    • 三色标记法
    • STW(Stop The World)
  • GC优化
    • 写屏障
    • 协助GC
  • GC触发的时机
    • 内存分配量到达阈值触发GC
    • 定期触发GC
    • 手动触发
  • GC 性能优化

常见GC算法

引用计数

每个对象维护一个计数器,当引用该对象的对象被销毁时,计数器减一,当计数器为0时回收该对象。
代表语言:Python,PHP,Swift
优点:对象可以很快被回收,不会出现内存耗尽再回收的现象。
缺点:不能很好的处理循环引用,而且维护计数器需要开销。

标记清除

从根变量开始便利所有引用对象,当引用对象没有标记“被引用”,则回收该对象。
代表语言:GO(三色标记法)
优点:解决引用计数的缺点。
缺点:需要STW,暂时停止程序运行。

分代收集

按照对象的证明周期长短划分不同代空间,生命周期长的放入老年代,生命周期短的放入新生代,不同代有不用的回收算法以及回收频率。
代表语言:Java
优点:回收性能好。
缺点:算法复杂。

Go的GC

mark内存标记

在span的数据结构中维护位图allocBits表示内存块分配情况,同时还维护另一个位图gcmarkBits记录每块内存的标记情况。由于allocBits与gcmarkBits数据结构相同,回收时将allocBits指向gcmarkBits,表示只有标记过的内存才是存活的。gcmarkBits会在下次标记时重新分配内存。

三色标记法

灰色:对象还在标记队列中等待。
黑色:对象已被标记,gcmarkBits对应的位为1(该对象不会被本次GC清理)。
白色:对象未被标记,gcmarkBits对应的位为0(该对象会被本次GC清理)。
初始状态下所有对象都是白色。
例:
根对象引用了对象A、B、C,则A、B、C变为灰色对象。接下来分析对象A、B、C是否引用其他对象。如果只有C引用对象D,那么对象A、B、C变为黑色对象,对象D变为灰色,再分析对象D是否引用其他对象,如果有再进行类似以上操作,如果没有则仅将对象D变为黑色对象。

STW(Stop The World)

Go中的STW就是停止所有的goroutine,专心做垃圾回收,等待回收完毕再恢复goroutine。

GC优化

主要缩短STW时间,不断优化GC算法。

写屏障

写屏障的作用是使goroutine与GC同时运行的手段。能够大大缩短STW时间。
GC过程中新分配的内存不会被立即标记,用的正是写屏障技术,即GC过程中分配的内存不会在本次GC中清理。

协助GC

为了防止内存分配过快,在GC过程中如果goroutine需要分配内存,那么改goroutine会参与一部分GC工作。这种机制称为Mutator Assist。

GC触发的时机

内存分配量到达阈值触发GC

每次分配内存时检查当前内存分配量是否达到阈值,如果达到则启用GC。

阈值 = 上一次GC内存分配量 x 内存增长率

内存增长率由环境变量GOGC控制,默认为100。每当内存扩大一倍时启动GC。

定期触发GC

默认情况下,最长两分钟触发一次GC,在src/runtime/:forcegcperiod中定义

var forcegcperiod int64 = 2 * 60 * 1e9
  • 1

手动触发

在程序中使用()手动触发GC,主要用于GC性能测试以及统计。

GC 性能优化

对象越多,GC性能越低。所以优化GC性能的思路之一为减少对象分配个数,比如对象复用或者大对象组合多个小对象等。