golang 垃圾回收(GC)分析

之前写过一篇GC的总结,但是太过简陋。现在重拾八股,又有了很多疑问,重新总结一下GC的原理

golang采用的GC算法是三色标记法+混合写屏障

三色标记法其实是标记清除算法的一种,主要分为两个过程:标记和清除

三色标记法

三色标记法标记过程主要通过三个阶段的标记来确定哪些对象需要清除:

  1. 第一步,程序创建之初,所有的对象都被标记为白色,放到白色集合中
  2. 第二步,在GC开始的时候,会从根节点开始遍历,把遍历的到的白色对方放到灰色集合中
  3. 第三步,遍历灰色对象结合,将拿出的灰色对象引用到的对象放入灰色集合集合,将这个被拿出的灰色对象放入到黑色集合中
  4. 然后重复第三步,直到灰色集合中再没有对象
  5. 最后就是清除阶段,回收掉所有的白色对象,就是垃圾回收

这个算法其实就是广搜的思想,单向图从根节点遍历所有能遍历到的节点,遍历不到就是白色对象,就是GC需要回收的垃圾

如果只是单独的三色标记清楚是有问题的,就是如果GC期间产生了对象丢失问题,比如黑色对象引用了一个白色的对象,同时这个白色对象和它上游的灰色对象引用关系遭到破坏,那么这个白色对象和它的下游对象就会在清除阶段被清除。

解决这种方法最简单的办法是stw(stop the world)

STW

就是让程序暂停,这样GC期间对象就不会更改,但是这样会让程序发生卡顿,这对所有的用户程度都有很大影响

屏障技术

当然还有其他方法,就是从产生这种问题的源头入手:

  1. 黑色对象引用了白色对象
  2. 同时白色对象和它上游的灰色对象引用关系被破坏

由此产生了两种思想,就是强-弱三色不变式

(1) 强三色不变式:强制性的不允许黑色对象引用到白色对象

(2) 弱三色不变式:不再强制不允许引用,但是黑色对象引用的白色对象的上游必须有灰色对象保护,这样就可以保护白色对象

基于对上述两种思想,golang算法演进了两种屏障方式"插入屏障"、"删除屏障"

  • 插入屏障(强三色):
    • 在A对象引用B对象的时候,将B对象标记城灰色
    • 但是栈不会标记,因为栈函数调用需要频繁使用,这样栈上新加的对象依旧是白色。需要在GC之后启动stw对栈进行扫描
  • 删除屏障(弱三色):
    • 被删除的对象,如果本身是灰色或者白色,那么被标记成灰色
    • 这种回收方式精度低,一个对象即使被删了依旧可以活过这一轮GC

混合写屏障

在1.8版本启用了混合写屏障,来减少stw的时间

  • 规则如下:

    1. GC开始时,优先扫描栈,将栈上所有可以扫描到的对象标记成黑色(之后不需要进行二次重复扫描,无需stw)。之后会开始三色标记
    2. GC期间,栈上创建的新对象,均标记成黑色
    3. 堆上被删除的对象标记成灰色
    4. 堆上被添加的对象标记成灰色
  • 这个其实是变形的弱三色不变式,而且屏障技术并不引用在栈上,要保证栈的运行效率

  • 几个案例分析

    • 对象被一个堆对象删除引用,成为栈对象的下游
    • 对象被一个堆对象删除引用,成为另一个栈对象的下游
    • 对象被一个栈对象删除引用,成为另一个栈对象的下游
    • 对象被一个栈对象删除引用,成为另一个堆对象的下游
  • 延伸一下:

    • GC期间,在扫描栈之后,栈上黑色对象是无法引用到白色对象的,比如对象9引用对象5
    • 为什么呢,因为这些对象是不可到达的,如果可到达就不会被标记成白色了,就比如局部变量的在被调用结束之后,生命周期立刻结束。

值得注意的是,混合写屏障同样在栈上不生效,只在堆空间启动,而且标记阶段几乎不用stw。所以三色标记+回合写屏障,效率极高

v1.8版本GC过程

  • STW,开启混合写屏障,扫描栈对象
  • 三色标记启动
  • STW,关闭混合写屏障
  • 在后台进行GC(利用并发优势)

参考: 刘丹冰老师的GC分析

相关推荐
2401_857622661 小时前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php
2402_857589361 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
哎呦没3 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
_.Switch3 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
杨哥带你写代码4 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
AskHarries5 小时前
读《show your work》的一点感悟
后端
A尘埃5 小时前
SpringBoot的数据访问
java·spring boot·后端
yang-23075 小时前
端口冲突的解决方案以及SpringBoot自动检测可用端口demo
java·spring boot·后端
Marst Code5 小时前
(Django)初步使用
后端·python·django
代码之光_19805 小时前
SpringBoot校园资料分享平台:设计与实现
java·spring boot·后端