rwa*_*ace 14 compiler-construction garbage-collection language-implementation
在实现精确的垃圾收集时,总是存在弄清堆栈上哪些字是指针以及哪些是其他类型的数据(如整数或浮点数)的问题.解释语言通常通过使所有东西成为指针来解决这个问题; 某些语言(如Lisp)的编译器通常使用标记位来区分指针和整数来解决它.
但是Java和C#等语言的JIT编译器如何支持完整的无盒装机器字整数和浮点数?他们如何判断堆栈和CPU寄存器的哪些内容是指针?
nom*_*olo 10
这些语言的字节码始终包含完整类型信息.它存储在元数据中(例如,用于参数类型)或隐含在操作码中(例如,可以存在用于添加整数或浮点数的不同操作码).
优化代码时,编译器可以访问此信息并使用它来改进优化.它还使用该信息为特定GC安全点处的已编译代码生成元数据.
GC安全点是代码中的一个位置,可以安全地中断线程以安排另一个线程或执行垃圾回收.在GC安全点,我们有必要的元数据可以找出哪些寄存器包含指针而哪些寄存器不包含指针.例如,在Hotspot JVM中,循环始终包含来自内存中特殊位置的读取.该读取的结果未使用,但如果指令读取的地址被读保护,则发生页面错误.这可以通过简单地将该页面设置为只读来用于在任意时间点中断线程.一旦线程被中断,我们就会查看程序计数器,然后在哈希表中查找元数据.
其他需要GC安全点的地方是分配站点:分配可能会失败并导致GC发生.您可以通过一次为多个对象分配内存来减少安全点数.
编辑:请注意,使用GC安全点只是众多选项中的一种.正如SK逻辑所提到的,另一个选择是为指针和非指针使用单独的堆栈.很明显,在GC期间需要遍历一个堆栈的所有元素,而不是其他元素.不过,你仍然需要注意寄存器中的指针.例如,只要寄存器中有实时指针,堆栈上也必须存在相同的指针.
第三种选择是使用一个阴影堆栈,该堆栈包含一个链接的指针列表,用于堆叠生活在真实堆栈上的根.有关详细信息,请参阅Fergus Henderson撰写的文章"不合作环境中的准确垃圾收集"(PDF).