面试题答案
一键面试Go语言写屏障在垃圾回收场景下的作用
- 解决三色标记法中的对象丢失问题
- 在Go语言的垃圾回收中,采用三色标记法来标记存活对象。三色分别为白色(未被标记)、灰色(已被标记,但其子对象还未被标记)、黑色(已被标记,且其所有子对象也都被标记)。
- 并发垃圾回收过程中,当应用程序在标记阶段修改对象引用关系时,如果没有写屏障,可能会出现对象丢失的情况。例如,一个白色对象原本被灰色对象引用,在标记过程中,灰色对象对白色对象的引用被移除,同时没有其他灰色对象引用该白色对象,且该白色对象又被分配给了一个黑色对象(在黑色对象标记完成后进行的赋值操作),这样这个白色对象就会被错误地当作垃圾回收,因为垃圾回收器不会再遍历到它。
- 写屏障的作用就是通过在对象引用关系发生变化时采取一些措施,防止上述对象丢失问题的发生,确保所有存活对象最终都能被正确标记。
- 保证垃圾回收的正确性
- 写屏障能够在对象引用关系变化时,将新的引用关系记录下来,使得垃圾回收器能够感知到这些变化。它使得垃圾回收器在并发执行时,即使应用程序在不断修改对象的引用关系,也能正确地标记出所有存活对象,从而保证垃圾回收过程的正确性。
写屏障协助垃圾回收器标记存活对象的方式
- 插入写屏障(写时复制写屏障)
- 原理:在将一个白色对象赋值给黑色对象的字段时,会将这个白色对象添加到灰色集合中。例如,当执行
a.b = c
(假设a
是黑色对象,c
是白色对象)操作时,写屏障会在赋值操作前,将c
对象标记为灰色。 - 作用:这样即使
a
已经被标记为黑色,c
对象也不会因为被a
引用而被遗漏,垃圾回收器后续遍历灰色集合时会标记c
及其子对象,保证了所有存活对象都能被正确标记。
- 原理:在将一个白色对象赋值给黑色对象的字段时,会将这个白色对象添加到灰色集合中。例如,当执行
- 删除写屏障
- 原理:当一个灰色对象对白色对象的引用被移除时,会将这个白色对象标记为灰色。例如,当执行
a.b = nil
(假设a
是灰色对象,a.b
原本指向一个白色对象)操作时,写屏障会在赋值操作后,将原本a.b
指向的白色对象标记为灰色。 - 作用:防止因为灰色对象对白色对象引用的移除而导致白色对象被错误地当作垃圾,确保垃圾回收器能够继续追踪该白色对象及其子对象,从而正确标记存活对象。
- 原理:当一个灰色对象对白色对象的引用被移除时,会将这个白色对象标记为灰色。例如,当执行
- 混合写屏障
- 原理:Go语言在1.8版本引入了混合写屏障。混合写屏障结合了插入写屏障和删除写屏障的优点。在垃圾回收的标记阶段,对于新分配的对象,直接标记为黑色;对于非新分配的对象,在写操作时,将被写入的对象(即新的引用目标对象)标记为灰色。
- 作用:混合写屏障使得垃圾回收器在并发垃圾回收过程中,既能减少写屏障带来的额外开销(因为新分配对象直接标记为黑色),又能保证标记的正确性,从而更高效地标记存活对象。它在保证垃圾回收正确性的同时,降低了写屏障对应用程序性能的影响,提高了整体的垃圾回收效率。