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

cut*_*lus 4 garbage-collection haskell ghc

在64位平台上,int由于指针标记,OCaml的类型为63位.这允许整数被打开,并且仍然可以在运行时与指针区分开来,从而实现精确的GC.IIRC,GHC RTS中的GC也是精确的,但GHC的Int是64位,它们可以是未装箱的.如果是这种情况,那么运行时系统如何区分Ints和指针?看来,区分其他未装箱的字大小值和指针也会产生同样的问题.

zen*_*ack 6

简短版本是:将值分配给所有指针和所有非指针组合在一起,并包含一些元数据,以便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(...) -> ...
Run Code Online (Sandbox Code Playgroud)

这样做的结果是价值已经足够了解自己做簿记,而对于一些常见的布局,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如何映射到硬件.这是一个引人入胜的读物,其中有很多简洁的东西与大多数(严格的)函数语言的实现方式大不相同.这篇论文很旧,但仍然相关.


chi*_*chi 1

本质上,GHC RTS 文档对此进行了描述,其中详细介绍了堆对象的格式,包括标头和有效负载。

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

这意味着任何堆对象都会有一个字的开销。