Language agnostic 三色增量更新GC:是否需要扫描每个堆栈两次?
让我给你一个三色GC的简短介绍(以防有人读到它却从未听说过它);如果你不在乎,跳过它,跳转到问题上来 三色GC的工作原理 在三色GC中,对象具有三种可能颜色中的一种;白色、灰色和黑色。三色GC可描述如下:Language agnostic 三色增量更新GC:是否需要扫描每个堆栈两次?,language-agnostic,garbage-collection,Language Agnostic,Garbage Collection,让我给你一个三色GC的简短介绍(以防有人读到它却从未听说过它);如果你不在乎,跳过它,跳转到问题上来 三色GC的工作原理 在三色GC中,对象具有三种可能颜色中的一种;白色、灰色和黑色。三色GC可描述如下: 所有对象最初都是白色的 由于全局变量或堆栈变量引用而可访问的所有对象(“根对象”)均为灰色 我们取任何灰色的物体,找到它对白色物体的所有引用,并将这些白色物体涂成灰色。然后我们把物体本身涂成黑色 只要有灰色对象,我们就继续执行步骤3 如果我们不再有灰色对象,所有剩余的对象都是白色或黑色 所有的
stack -> A.ref -> B
现在GC开始一个循环,停止线程,扫描堆栈,并将a视为可直接访问,将其着色为灰色。一旦扫描完整个堆栈,它将再次取消暂停线程,并在步骤(3)开始处理。在开始执行任何操作之前,它将被抢占(可能发生)线程再次运行并执行以下代码:
localRef = A.ref; // localRef points to B
A.ref = NULL; // Now only the stack points to B
sleep(10000); // Sleep for the whole GC cycle
由于未违反不变量,B为白色,但未分配给黑色对象,B的颜色未改变,仍然为白色。a不再指B,因此在处理“灰色”时A,B不会改变颜色,A会变成黑色。在循环结束时,B仍然是白色,看起来像垃圾。但是,localRef指的是B,因此它不是垃圾
问题
我说得对吗,三色GC必须扫描每个线程的堆栈两次?一开始扫描一次,以识别根对象(得到灰色)在删除白色对象之前,这些对象可能会被堆栈引用,即使没有其他对象再引用它们。到目前为止,我所看到的算法描述中没有提到任何关于扫描堆栈两次的内容。他们都只说,在并发使用时,始终强制执行不变量非常重要,否则会丢失可访问的对象。但就我所见,这还不够。堆栈必须被视为一个大对象,一旦扫描,“堆栈为黑色”,堆栈的每个引用更新都必须使对象变为灰色
如果真是这样的话,使用增量更新可能比我最初认为的更棘手,并且有一些性能缺陷,因为堆栈更改是所有更改中最频繁的一个。一点术语: 让我列举一些名称,以便更清楚地解释 变量是数据的任何插槽,它可能包含指针,并且可能随时间而变化。这包括全局变量、局部变量、CPU寄存器和分配对象中的字段 在三色增量或并发GC中,有三种类型的变量: