Haskell运行时如何区分指针和未装箱的单词大小的值



在64位平台上,由于指针标记,OCaml的int类型为63位。这使得int可以开箱,并且在运行时仍然可以与指针区分,从而实现精确的GC。IIRC,GHC RTS中的GC也很精确,但GHC的Int是64位的,可以开箱。如果是这样的话,那么运行时系统如何区分Ints和指针?在区分其他未装箱的单词大小的值和指针时,似乎也会出现同样的问题。

简短的版本是:分配值时将所有指针和所有非指针分组在一起,并包括一点元数据,以便GC知道接下来要执行什么。

请注意,Haskell报告实际上允许Int为31或63位,从而使OCaml策略有效——但GHC并不是这样做的。

稍长的版本是,所说的"元数据"实际上是垃圾收集器使用的两个函数。为了给出一个粗略的草图,您可以将Haskell中的值视为在运行时用方法表示为OO风格的对象:

class Fn:
# By far the most used; this evaluates the value:
enter(...) -> ...
# Used by the garbage collector:
scavenge(...) -> ...
evacuate(...) -> ...

这样做的结果是,值对自己有足够的了解来进行记账,对于一些常见的布局,GHC定义了这些函数的专用版本;垃圾收集器可能基本上忽略了清除和排空的确切工作方式。指针的分离&非指针是为了在常见情况下可以制作和共享通用实现。

请注意,即使对于不是"函数"的Haskell值,也存在"enter"函数,因为惰性意味着即使类型是例如Int,求值也可能涉及计算。

如果你想要很长的版本,我建议阅读:

https://www.microsoft.com/en-us/research/publication/implementing-lazy-functional-languages-on-stock-hardware-the-spineless-tagless-g-machine/

其中详细介绍了Haskell是如何映射到硬件的。这是一本引人入胜的读物,里面有很多巧妙的东西,与大多数(严格的)函数语言的实现方式有很大不同。这篇论文很旧,但仍然很有意义。

从本质上讲,这在GHC RTS文档中进行了描述,其中详细说明了堆对象的格式,包括标头和有效负载。

标头描述有效负载的哪些字是指针,以便垃圾收集可以工作。

这意味着,粗略地说,任何堆对象都有一个单词的开销。

相关内容

  • 没有找到相关文章

最新更新