面试题答案
一键面试写屏障的作用
在Go语言采用三色标记法进行垃圾回收时,写屏障的作用主要是解决在垃圾回收过程中对象引用关系变化可能导致的误判问题,保证垃圾回收的正确性。三色标记法将对象分为白色、灰色和黑色三种颜色,白色代表未被访问的对象,灰色代表已被访问但其子对象尚未被访问的对象,黑色代表已被访问且其子对象也都被访问过的对象。在垃圾回收过程中,对象的引用关系可能会动态变化,如果没有写屏障,可能会出现本应存活的对象被错误地标记为垃圾(即“悬挂指针”问题)。写屏障通过在对象引用关系发生变化时采取相应措施,来避免这种情况的发生。
通过写屏障保证垃圾回收正确性的实现
- 插入写屏障(Insertion Write Barrier)
- 工作原理:在新的引用关系建立时,即当一个对象被赋值给另一个对象的指针字段时,将新被引用的对象标记为灰色。例如,假设有对象A和对象B,当执行
A.field = B
操作时,插入写屏障会将B标记为灰色。这样做的目的是确保新被引用的对象B在本次垃圾回收过程中不会被误判为垃圾,因为它被A引用,即使A可能在后续被标记为黑色,B也能通过灰色标记被后续处理。 - 代码示例(伪代码):
- 工作原理:在新的引用关系建立时,即当一个对象被赋值给另一个对象的指针字段时,将新被引用的对象标记为灰色。例如,假设有对象A和对象B,当执行
func setPointer(a *Object, field *Object, b *Object) {
// 插入写屏障操作
if isGCInProgress() {
markAsGray(b)
}
a.field = b
}
- 删除写屏障(Deletion Write Barrier)
- 工作原理:在对象的引用关系被删除时,即当一个对象的指针字段被赋值为nil或者指向另一个对象时,将原被引用的对象标记为灰色(如果它此时不是黑色)。例如,当执行
A.field = nil
或者A.field = C
时(假设原来A.field = B
),如果B不是黑色,删除写屏障会将B标记为灰色。这样可以保证即使B失去了从A的直接引用,在本次垃圾回收过程中也不会被误判为垃圾,因为它可能通过其他路径仍然存活。 - 代码示例(伪代码):
- 工作原理:在对象的引用关系被删除时,即当一个对象的指针字段被赋值为nil或者指向另一个对象时,将原被引用的对象标记为灰色(如果它此时不是黑色)。例如,当执行
func setPointer(a *Object, field *Object, b *Object) {
old := a.field
// 删除写屏障操作
if isGCInProgress() &&!isBlack(old) {
markAsGray(old)
}
a.field = b
}
- 混合写屏障(Hybrid Write Barrier)
- 工作原理:Go语言自Go 1.8版本开始采用混合写屏障,它结合了插入写屏障和删除写屏障的优点。混合写屏障在对象被分配时将其标记为灰色,并且在对象的指针字段被赋值时,将新被引用的对象标记为灰色(类似插入写屏障),同时将原被引用的对象标记为灰色(类似删除写屏障)。这种方式既保证了新对象和新引用关系的正确性,也兼顾了旧引用关系删除时对象的存活判断,在性能和正确性之间取得了较好的平衡。
- 优点:混合写屏障可以减少垃圾回收过程中的“STW”(Stop The World,即暂停应用程序的运行)时间,因为它在垃圾回收期间对应用程序的影响相对较小。同时,由于在对象分配时就标记为灰色,减少了垃圾回收扫描的工作量,提高了垃圾回收的效率。