一 经典的GC算法
  1. 引用计数(reference counting)
  2. 标记-清扫(mark & sweep)
  3. 复制收集(Copy and Collection)
二 标记-清扫(mark & sweep)算法

golang的gc算法主要是基于标记-清扫(mark & sweep)算法,在了解go的gc先了解一下传统的标记-清扫(mark & sweep)算法。
这个算法有2个操作

  • 标记
  • 清除

mark and sweep算法在执行的时候,需要程序暂停( stop the world ),大致的步骤是:

  1. stop the world 暂停程序执行
  2. 找到root根对象可以到达的对象做好标记
  3. 清除没有做标记的对象
  4. start the world 开始程序执行

三 golang的清除流程 (三色并发标记) 分4个阶段

第一个阶段 gc开始 (stw)

  1. stop the world 暂停程序执行
  2. 启动标记工作携程( mark worker goroutine ),用于第二阶段
  3. 启动写屏障
  4. 将root 跟对象放入标记队列(放入标记队列里的就是灰色)
  5. start the world 取消程序暂停,进入第二阶段

第二阶段 marking(这个阶段,用户程序跟标记携程是并行的)

  1. 从标记队列里取出对象,标记为黑色
  2. 然后检测是否指向了另一个对象,如果有,将另一个对象放入标记队列
  3. 在扫描过程中,用户程序如果新创建了对象 或者修改了对象,就会触发写屏障,将对象放入单独的 marking队列,也就是标记为灰色
  4. 扫描完标记队列里的对象,就会进入第三阶段

第三阶段 处理marking过程中修改的指针 (stw)

  1. stop the world 暂停程序
  2. 将marking阶段 修改的对象 触发写屏障产生的队列里的对象取出,标记为黑色
  3. 然后检测是否指向了另一个对象,如果有,将另一个对象放入标记队列
  4. 扫描完marking队列里的对象,start the world 取消暂停程序 进入第四阶段

第四阶段 sweep 清楚白色的对象
到这一阶段,所有内存要么是黑色的要么是白色的,清楚所有白色的即可
golang的内存管理结构中有一个bitmap区域,其中可以标记是否“黑色”

四 golang gc 的触发
  • 触发内存的阀值,内存达到上次gc后的2倍
  • 2分钟
  • 手动触发