标签:height 包含 实现原理 aced locate alt rev access 内存
在之前的Go语言——内存管理一文中,分析过span是内存管理的最小单位,所以猜测gc的粒度也是span。
type mspan struct { // allocBits and gcmarkBits hold pointers to a span‘s mark and // allocation bits. The pointers are 8 byte aligned. // There are three arenas where this data is held. // free: Dirty arenas that are no longer accessed // and can be reused. // next: Holds information to be used in the next GC cycle. // current: Information being used during this GC cycle. // previous: Information being used during the last GC cycle. // A new GC cycle starts with the call to finishsweep_m. // finishsweep_m moves the previous arena to the free arena, // the current arena to the previous arena, and // the next arena to the current arena. // The next arena is populated as the spans request // memory to hold gcmarkBits for the next GC cycle as well // as allocBits for newly allocated spans. // // The pointer arithmetic is done "by hand" instead of using // arrays to avoid bounds checks along critical performance // paths. // The sweep will free the old allocBits and set allocBits to the // gcmarkBits. The gcmarkBits are replaced with a fresh zeroed // out memory. allocBits *gcBits gcmarkBits *gcBits }
如图所示,通过gcmarkBits位图标记span的块是否被引用。对应内存分配中的bitmap区。
例如,当前内存中有A~F一共6个对象,根对象a,b本身为栈上分配的局部变量,根对象a、b分别引用了对象A、B, 而B对象又引用了对象D,则GC开始前各对象的状态如下图所示:
stop the world是gc的最大性能问题,对于gc而言,需要停止所有的内存变化,即停止所有的goroutine,等待gc结束之后才恢复。
目前整个GC流程会进行两次STW(Stop The World), 第一次是Mark阶段的开始, 第二次是Mark Termination阶段.
需要注意的是, 不是所有根对象的扫描都需要STW, 例如扫描栈上的对象只需要停止拥有该栈的G.
从go 1.9开始, 写屏障的实现使用了Hybrid Write Barrier, 大幅减少了第二次STW的时间.
因为go支持并行GC, GC的扫描和go代码可以同时运行, 这样带来的问题是GC扫描的过程中go代码有可能改变了对象的依赖树。
例如开始扫描时发现根对象A和B, B拥有C的指针。
为了避免这个问题, go在GC的标记阶段会启用写屏障(Write Barrier).
启用了写屏障(Write Barrier)后,
即使A可能会在稍后丢掉C, 那么C就在下一轮回收。
开启写屏障之后,当指针发生改变, GC会认为在这一轮的扫描中这个指针是存活的, 所以放入灰色。
首先标记root跟对象,根对象的子对象也是存活的。
根对象包括:全局变量,各个G stack上的变量等。
标签:height 包含 实现原理 aced locate alt rev access 内存
原文地址:https://www.cnblogs.com/saryli/p/10105393.html