插入/删除写屏障

https://www.cnblogs.com/cxy2020/p/16321884.html
https://developer.aliyun.com/article/861507

  • 插入/删除写屏障都存在漏(少)回收,但是不会误(多)回收

  • 插入写屏障可以认为是一个保守设计,所有新分配的堆对象如果被黑/灰对象指向都标记为灰色,在下一轮GC再回收。缺点是标记完回栈上扫一遍需要stw。

  • 删除写屏障也可以认为是一个保守设计,需要所有可达根对象被标记了(期间stw)才能开启删除写屏障。缺点是


为了避免内存空间错误释放,需要stw,为了不stw,推出三色不变性,负责该原则就不需要stw。

强三色不变式(对应插入写屏障)

不允许黑色对象引用白色对象

image.png
  • 插入写屏障

具体操作:A,新增对象B且添加A->B,插入的新对象B标记为灰色。

writePointer(slot, ptr):
shade(ptr)
*slot = ptr

插入屏障仅会在堆内存(父节点是堆对象)中生效,不对栈内存空间生效(在栈上指向新对象时不会置黑),这是因为go在并发运行时,数十万goroutine的栈都进行屏障保护自然会有性能问题。

image.png
image.png

弊端:由于栈上的对象没有插入写机制,在扫描完成后,仍然可能存在栈上的白色对象指向黑色的堆对象,所以在最后需要对栈上的空间进行STW,防止对象误删除。

弱三色不变式

黑色对象可以引用白色对象,但是白色对象的上游必须存在灰色对象

image.png
  • 删除写屏障

具体操作:A->B,删除->,则被删除的对象B标记为灰色。

writePointer(slot, ptr):
shade(*slot)
*slot = ptr

删除写屏障(基于起始快照的写屏障)有一个前提条件,就是起始的时候,把整个根部扫描一遍,让所有的可达对象全都在灰色保护下(根黑,下一级在堆上的全灰),之后利用删除写屏障捕捉内存写操作,确保弱三色不变式不被破坏,就可以保证垃圾回收的正确性(但是需要stw)。

image.png
image.png

一个对象的引用被删除后,即使没有其他存活的对象引用它,它仍然会活到下一轮。如此一来,会产生很多的冗余扫描成本,且降低了回收精度。

image.png

混合写屏障

  • 插入写屏障:结束时需要STW来重新扫描栈,标记栈上引用的白色对象的存活;

  • 删除写屏障:回收精度低,GC开始时STW扫描堆栈来记录初始快照,这个过程会保护开始时刻的所有存活对象。

GC期间,任何在栈上新创建的对象,均为黑色。GC刚开始的时候,会将栈上的可达对象全部标记为黑色(解除删除写屏障的stw)。屏障限制只在堆内存中生效,且栈上全部标记黑色无需stw,提升了GC效率。

1、GC开始将栈上的可达对象全部扫描并标记为黑色 (之后不再进行第二次重复扫描,无需STW)

2、GC期间,任何在栈上创建的新对象,均为黑色。(惰性回收)(解除了删除写屏障的stw)

3、插入写屏障+删除写屏障(堆上元素指向其他对象的时候开启)

  • 全程没有stw
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容