面试题答案
一键面试Go语言垃圾回收的三色标记法
- 三色定义
- 白色:表示尚未被垃圾回收器访问到的对象。在垃圾回收开始阶段,所有对象都是白色。
- 灰色:表示自身已被垃圾回收器访问到,但它引用的对象还没有全部被访问。
- 黑色:表示自身及它引用的所有对象都已被垃圾回收器访问过。
- 标记过程
- 初始阶段:所有对象都是白色,从根对象(如全局变量、栈上的变量等)开始扫描。根对象被标记为灰色,放入灰色队列。
- 标记阶段:从灰色队列中取出一个对象,将其标记为黑色,并扫描它引用的对象。如果这些被引用对象是白色,则将它们标记为灰色并放入灰色队列。不断重复这个过程,直到灰色队列为空。此时,白色对象就是垃圾,黑色对象是存活对象。
写屏障与三色标记法协同工作避免对象误判
- 浮动垃圾问题:在标记过程中,如果应用程序并发修改对象的引用关系,可能会导致一些原本可达的对象(应该是存活的)在标记结束后被误判为白色(垃圾),这些对象被称为浮动垃圾。例如,一个黑色对象原本引用一个白色对象,在标记过程中,黑色对象对白色对象的引用被删除,同时没有其他灰色对象引用该白色对象,那么这个白色对象就可能被误判为垃圾。
- 写屏障原理:写屏障是一种在对象引用关系发生变化时执行的特殊代码。在Go语言中,使用的是插入写屏障(目前Go 1.8及之后版本)。
- 插入写屏障:当一个对象(假设为A)对另一个对象(假设为B)建立新的引用时,如果A是黑色,写屏障会将B标记为灰色。这样做的目的是确保在标记过程中,新建立的引用关系能够被垃圾回收器正确追踪,避免因为引用关系的动态变化导致对象误判为垃圾。具体来说,写屏障在对象引用赋值操作(如
a.b = c
)时,会在赋值操作之前或之后(取决于实现细节),将c
标记为灰色(如果c
原本是白色),从而保证c
在后续的标记过程中会被扫描,不会被误判为垃圾。
- 插入写屏障:当一个对象(假设为A)对另一个对象(假设为B)建立新的引用时,如果A是黑色,写屏障会将B标记为灰色。这样做的目的是确保在标记过程中,新建立的引用关系能够被垃圾回收器正确追踪,避免因为引用关系的动态变化导致对象误判为垃圾。具体来说,写屏障在对象引用赋值操作(如
通过写屏障与三色标记法的协同工作,Go语言的垃圾回收器能够在并发环境下准确地识别存活对象和垃圾对象,提高垃圾回收的准确性和效率。