Golang GC原理

1、内存泄漏

内存泄露,是从操做系统的角度上来阐述的,形象的比喻就是“操做系统可提供给全部进程的存储空间(虚拟内存空间)正在被某个进程榨干”,致使的缘由就是程序在运行的时候,会不断地动态开辟的存储空间,这些存储空间在在运行结束以后后并无被及时释放掉。应用程序在分配了某段内存以后,因为设计的错误,会致使程序失去了对该段内存的控制,形成了内存空间的浪费。golang

若是程序在内存空间内申请了一块内存,以后程序运行结束以后,没有把这块内存空间释放掉,并且对应的程序又没有很好的gc机制去对程序申请的空间进行回收,这样就会致使内存泄露。性能

2、GC原理

root

首先标记root根对象,根对象的子对象也是存活的。优化

根对象包括:全局变量,各个G stack上的变量等。spa

标记

span是内存管理的最小单位,因此猜想gc的粒度也是span。操作系统

如图所示,经过gcmarkBits位图标记span的块是否被引用。对应内存分配中的bitmap区。设计

三色标记

  • 灰色:对象已被标记,但这个对象包含的子对象未标记
  • 黑色:对象已被标记,且这个对象包含的子对象也已标记,gcmarkBits对应的位为1(该对象不会在本次GC中被清理)
  • 白色:对象未被标记,gcmarkBits对应的位为0(该对象将会在本次GC中被清理)

例如,当前内存中有A~F一共6个对象,根对象a,b自己为栈上分配的局部变量,根对象a、b分别引用了对象A、B, 而B对象又引用了对象D,则GC开始前各对象的状态以下图所示:指针

  1. 初始状态下全部对象都是白色的。
  2. 接着开始扫描根对象a、b; 因为根对象引用了对象A、B,那么A、B变为灰色对象,接下来就开始分析灰色对象,分析A时,A没有引用其余对象很快就转入黑色,B引用了D,则B转入黑色的同时还须要将D转为灰色,进行接下来的分析。
  3. 灰色对象只有D,因为D没有引用其余对象,因此D转入黑色。标记过程结束
  4. 最终,黑色的对象会被保留下来,白色对象会被回收掉。
 

STW

stop the world是gc的最大性能问题,对于gc而言,须要中止全部的内存变化,即中止全部的goroutine,等待gc结束以后才恢复。orm

触发

  • 阈值:默认内存扩大一倍,启动gc
  • 按期:默认2min触发一次gc,src/runtime/proc.go:forcegcperiod
  • 手动:runtime.gc()

3、GC过程

GO的GC是并行GC, 也就是GC的大部分处理和普通的go代码是同时运行的, 这让GO的GC流程比较复杂.对象

  1. Stack scan:Collect pointers from globals and goroutine stacks。收集根对象(全局变量,和G stack),开启写屏障。全局变量、开启写屏障须要STW,G stack只须要中止该G就好,时间比较少。
  2. Mark: Mark objects and follow pointers。标记全部根对象, 和根对象能够到达的全部对象不被回收。
  3. Mark Termination: Rescan globals/changed stack, finish mark。从新扫描全局变量,和上一轮改变的stack(写屏障),完成标记工做。这个过程须要STW。
  4. Sweep: 按标记结果清扫span

目前整个GC流程会进行两次STW(Stop The World), 第一次是Stack scan阶段, 第二次是Mark Termination阶段.blog

  • 第一次STW会准备根对象的扫描,启动写屏障(Write Barrier)和辅助GC(mutator assist).
  • 第二次STW会从新扫描部分根对象,禁用写屏障(Write Barrier)和辅助GC(mutator assist).

从1.8之后的golang将第一步的stop the world 也取消了,这又是一次优化; 1.9开始, 写屏障的实现使用了Hybrid Write Barrier, 大幅减小了第二次STW的时间.

写屏障

由于go支持并行GC, GC的扫描和go代码能够同时运行, 这样带来的问题是GC扫描的过程当中go代码有可能改变了对象的依赖树。

例如开始扫描时发现根对象A和B, B拥有C的指针。

  1. GC先扫描A,A放入黑色
  2. B把C的指针交给A
  3. GC再扫描B,B放入黑色
  4. C在白色,会回收;可是A其实引用了C。

为了不这个问题, go在GC的标记阶段会启用写屏障(Write Barrier).

启用了写屏障(Write Barrier)后,在GC第三轮rescan阶段,根据写屏障标记将C放入灰色,防止C丢失。

相关文章
相关标签/搜索