一 经典的GC算法
- 引用计数(reference counting)
- 标记-清扫(mark & sweep)
- 复制收集(Copy and Collection)
二 标记-清扫(mark & sweep)算法
golang的gc算法主要是基于标记-清扫(mark & sweep)算法,在了解go的gc先了解一下传统的标记-清扫(mark & sweep)算法。
这个算法有2个操作
- 标记
- 清除
mark and sweep算法在执行的时候,需要程序暂停( stop the world ),大致的步骤是:
- stop the world 暂停程序执行
- 找到root根对象可以到达的对象做好标记
- 清除没有做标记的对象
- start the world 开始程序执行
三 golang的清除流程 (三色并发标记) 分4个阶段
第一个阶段 gc开始 (stw)
- stop the world 暂停程序执行
- 启动标记工作携程( mark worker goroutine ),用于第二阶段
- 启动写屏障
- 将root 跟对象放入标记队列(放入标记队列里的就是灰色)
- start the world 取消程序暂停,进入第二阶段
第二阶段 marking(这个阶段,用户程序跟标记携程是并行的)
- 从标记队列里取出对象,标记为黑色
- 然后检测是否指向了另一个对象,如果有,将另一个对象放入标记队列
- 在扫描过程中,用户程序如果新创建了对象 或者修改了对象,就会触发写屏障,将对象放入单独的 marking队列,也就是标记为灰色
- 扫描完标记队列里的对象,就会进入第三阶段
第三阶段 处理marking过程中修改的指针 (stw)
- stop the world 暂停程序
- 将marking阶段 修改的对象 触发写屏障产生的队列里的对象取出,标记为黑色
- 然后检测是否指向了另一个对象,如果有,将另一个对象放入标记队列
- 扫描完marking队列里的对象,start the world 取消暂停程序 进入第四阶段
第四阶段 sweep 清楚白色的对象
到这一阶段,所有内存要么是黑色的要么是白色的,清楚所有白色的即可
golang的内存管理结构中有一个bitmap区域,其中可以标记是否“黑色”
四 golang gc 的触发
- 触发内存的阀值,内存达到上次gc后的2倍
- 2分钟
- 手动触发