1

fixnum 问题让我想到了另一个我想了很久的问题。

许多关于垃圾收集的在线资料并没有说明如何实现运行时类型信息。因此,我对各种垃圾收集器了解很多,但并不真正了解如何实现它们。

fixnum 解决方案实际上非常好,很清楚哪个值是指针,哪个不是。还有哪些其他常用的存储类型信息的解决方案?

另外,我想知道 fixnum -thing。这是否意味着您仅限于每个数组索引上的 fixnums?或者是否有某种解决方法可以获得完整的 64 位整数?

4

2 回答 2

4

基本上,为了实现准确的标记,您需要元数据来指示哪些单词被用作指针,哪些不是。

这个元数据可以按引用存储,就像 emacs 一样。如果对于您的语言/实现,您不太关心内存使用,您甚至可以使引用大于单词(可能是单词的两倍),以便每个引用都可以携带类型信息及其单字数据。这样,您可以拥有一个完整大小的 32 位指针的固定编号,代价是所有引用都是 64 位。

或者,元数据可以与其他类型信息一起存储。因此,例如,一个类除了通常的函数指针表外,还可以包含数据布局的每个字一位,指示该字是否包含垃圾收集器应遵循的引用。如果您的语言具有虚拟调用,那么您必须已经有一种方法可以从对象中计算出要使用的函数地址,因此相同的机制将允许您计算出要使用的标记数据 - 通常您会添加一个额外的秘密指针每个对象的开始,指向构成其运行时类型的类。显然,对于某些动态语言,指向的类型数据需要在写入时复制,因为它是可修改的。

堆栈也可以做类似的事情——将准确的标记信息存储在代码本身的数据部分中,并让垃圾收集器检查存储的程序计数器和/或堆栈上的链接指针,和/或由堆栈放置在堆栈上的其他信息为此目的的代码,以确定堆栈的每一位与哪个代码相关,因此哪些字是指针。轻量级异常机制倾向于做类似的事情来存储关于代码中出现 try/catch 的信息,当然调试器也需要能够解释堆栈,所以这很可能与一堆其他东西一起折叠您已经在实现任何语言,包括具有内置垃圾收集的语言。

请注意,垃圾收集不一定需要准确的标记。您可以将每个单词视为一个指针,无论它是否真的存在,在垃圾收集器的“所有内容的大列表”中查找它,以确定它是否可以引用尚未标记的对象,如果所以将其视为对该对象的引用。这很简单,但代价当然是介于“非常慢”和“非常慢”之间,具体取决于 gc 用于查找的数据结构。此外,有时一个整数恰好与未引用对象的地址具有相同的值,并导致您保留一大堆本应收集的对象。所以这样的垃圾收集器不能提供关于未引用对象被收集的强有力的保证。这对于玩具实现或第一个工作版本可能很好,但不太可能受到用户的欢迎。

比如说,一种混合​​方法可以准确地标记对象,但不能准确标记堆栈中特别多毛的区域。例如,如果您编写的 JIT 可以创建代码,其中引用的对象地址仅出现在寄存器中,而不出现在您通常的堆栈槽中,那么您可能需要不准确地跟踪操作系统存储寄存器时的堆栈区域取消调度有问题的线程以运行垃圾收集器。这可能非常繁琐,因此一种合理的方法(可能导致代码变慢)是要求 JIT 始终在准确标记的堆栈上保留它正在使用的所有指针值的副本。

于 2008-10-21T15:11:27.857 回答
0

在 Squeak(我猜也是 Scheme 和许多其他动态语言)中SmallInteger,你有 31 位有符号整数类和任意大整数类,例如LargePositiveInteger. 很可能有其他表示形式,64 位整数或者作为完整对象或带有几个位作为“我不是指针”标志。

但是算术方法被编码为处理过流/不足流,因此如果将 1 添加到SmallInteger maxVal,则得到 2^30 + 1 作为 的实例LargePositiveInteger,如果从中减去 1,则得到 2^30 作为SmallInteger.

于 2009-04-02T21:23:48.533 回答