GC

如何观察go语言垃圾回收现象

  • GODEBUG=gctrace=1
  • go tool trace 命令
  • debug.ReadGCStats
  • runtime.ReadMemStats

有了垃圾回收为什么还会内存泄漏

  • 预期能被快速释放的内存因被根对象引用而没有得到迅速释放,如一个大全局对象
  • goroutine 泄漏

GC ROOT

  • 全局变量
  • 栈变量
  • 寄存器

为什么不选择标记整理

  • tcmalloc 算法基本没有碎片问题

为什么不选择分代

  • 分代回收的目的是主要回收新创建的对象,GO语言会通过逃逸分析将大部分对象分配到栈上,堆上大多数为老对象,分代回收意义不大

并发GC的问题

  • 漏标:扫描完的黑色对象引入了白色引用
  • 错标:扫描中的灰色对象,引用被删除

三色标记

  • 白色、灰色和黑色。白色对象表示该对象尚未被标记。灰色对象表示该对象正在被标记。黑色对象表示该对象已经被标记,并且其所有子对象也已经被标记

破坏垃圾回收正确性的条件

  • 赋值器修改对象图,导致某一黑色对象引用白色对象
  • 从灰色对象出发,到达白色对象的、未经访问过的路径被赋值器破坏
  • 强三色不变式:白色对象不能被黑色对象直接引用 ,
  • 弱三色不变式:白色对象可以被黑色对象引用,但要从某个灰对象出发仍然可达该白对象
  • 插入写屏障:保证当一个黑色对象指向一个白色对象前,会先触发屏障将白色对象置为灰色,满足强三色不变
  • 删除写屏障:保证当一个白色对象即将被上游删除引用前,会触发屏障将其置灰,之后再删除上游指向其的引用

存在的问题

  1. 没有解决错标的问题,
  2. 指针赋值都需要插入写屏障,增大性能开销,所以在栈上没有启动写屏障

混合写屏障:

  • GC 开始前,以栈为单位分批扫描,将栈中所有对象置黑
  • GC 期间,栈上新创建对象直接置黑
  • 堆对象正常启用插入写屏障
  • 堆对象正常启用删除写屏障

历程

  • Go 1.3 之前: 使用标记-清除算法。
  • Go 1.5: 引入了三色标记算法。
  • Go 1.8: 引入了混合写屏障。

GC触发时机

  • 主动触发,通过调用 runtime.GC 来触发 GC,此调用阻塞式地等待当前 GC 运行完毕。
  • 被动触发:
    • 使用系统监控,当超过两分钟没有产生任何 GC 时,强制触发 GC
    • 对象分配时触发,使用步调(Pacing)算法,其核心思想是控制内存增长的比例

如果内存分配速度超过了标记清除的速度怎么办

  • 在 mallocgc 调用时进行检查。当存在新的内存分配时,会暂停分配内存过快的那些 goroutine,并将其转去执行一些辅助标记(Mark Assist)的工作,从而达到放缓继续分配、辅助 GC 的标记工作的目的

GC调优

  • 99%的应用程序都不需要针对 GC 进行调优。
  • 合理化内存分配的速度、提高赋值器的 CPU 利用率
  • 降低并复用已经申请的内存
  • 可以非常简单粗暴地将 GOGC 调整为 1000

两次STW

  • 清扫终止和标记终止都需要STW
  • 并发标记前需要开启写屏障,标记后需要关闭写屏障,再清扫

GC原理

  • 并发标记主要是标记msapn中的gcmarks字段,通过这个字段可以查看内存块哪个是存货的

文档

文档

results matching ""

    No results matching ""