14

在实现精确的垃圾回收时,总是存在一个问题,即确定堆栈上的哪些字是指针,哪些是其他类型的数据,例如整数或浮点数。解释型语言通常通过将所有内容都变成指针来解决这个问题。某些语言(例如 Lisp)的编译器通常通过使用标记位来区分指针和整数来解决它。

但是对于 Java 和 C# 等支持完整未装箱机器字整数和浮点数的语言的 JIT 编译器呢?它们如何分辨堆栈和 CPU 寄存器的哪些内容是指针?

4

2 回答 2

10

此类语言的字节码始终包含完整的类型信息。它存储在元数据中(例如,用于参数类型)或隐含在操作码中(例如,可能存在用于添加整数或浮点数的不同操作码)。

优化代码时,编译器可以访问此信息并使用它来改进优化。它还使用这些信息在特定的GC 安全点为已编译代码生成元数据。

GC 安全点是代码中的一个位置,可以安全地中断线程以调度另一个线程或执行垃圾收集。在 GC 安全点,我们有必要的元数据来找出哪些寄存器包含指针,哪些不包含。例如,在 Hotspot JVM 中,循环始终包含从内存中特殊位置的读取。该读取的结果未被使用,但如果指令读取的地址受到读保护,则会发生页面错误。这可以用于在任意时间点中断线程,只需将该页面设置为只读即可。一旦线程被中断,我们就会查看程序计数器并在哈希表中查找元数据。

其他需要成为 GC 安全点的地方是分配站点:分配可能会失败并导致 GC 发生。您可以通过一次为多个对象分配内存来减少安全点的数量。

编辑:请注意,使用 GC 安全点只是众多选项之一。正如 SK-logic 所提到的,另一种选择是为指针和非指针使用单独的堆栈。很明显,一个堆栈的所有元素都需要在 GC 期间遍历,而其他元素则不需要。不过,您仍然必须小心寄存器中的指针。例如,每当寄存器中有一个活动指针时,堆栈中也必须存在相同的指针。

第三种选择是使用影子堆栈,其中包含指向位于真实堆栈上的堆栈根的指针链表。有关详细信息,请参阅Fergus Henderson 的论文“不合作环境中的准确垃圾收集” (PDF)

于 2011-09-11T15:36:38.000 回答
0

Java 和 C# 等语言以不需要精确收集的方式指定。一个实现可能使用保守的收集器,其中看起来像指针的位模式被视为指针(但实际上可能是整数或浮点数)。例如,Boehm 收集器是一个保守的收集器,可用于 JIT ed 语言。

于 2011-08-17T23:41:26.680 回答