Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell运行时如何区分指针和非固定字大小的值?_Haskell_Garbage Collection_Ghc - Fatal编程技术网

Haskell运行时如何区分指针和非固定字大小的值?

Haskell运行时如何区分指针和非固定字大小的值?,haskell,garbage-collection,ghc,Haskell,Garbage Collection,Ghc,在64位平台上,由于指针标记,OCaml的int类型为63位。这允许在运行时取消对int的绑定,并且仍然可以与指针区分开来,从而实现精确的GC。IIRC,GHC RTS中的GC也是精确的,但GHC的INT是64位的,可以取消绑定。如果是这样,那么运行时系统如何区分int和指针?区分其他非固定字大小的值和指针似乎也会出现同样的问题。简短的版本是:分配值时,所有指针和所有非指针都分组在一起,并包含一些元数据,以便GC知道接下来要做什么 注意,Haskell报告实际上允许Int为31或63位,这使得O

在64位平台上,由于指针标记,OCaml的
int
类型为63位。这允许在运行时取消对int的绑定,并且仍然可以与指针区分开来,从而实现精确的GC。IIRC,GHC RTS中的GC也是精确的,但GHC的INT是64位的,可以取消绑定。如果是这样,那么运行时系统如何区分int和指针?区分其他非固定字大小的值和指针似乎也会出现同样的问题。

简短的版本是:分配值时,所有指针和所有非指针都分组在一起,并包含一些元数据,以便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,计算也可能涉及计算

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


这涉及到Haskell如何映射到硬件的很多细节。这是一本引人入胜的书,里面有很多精巧的东西,与大多数(严格的)函数式语言的实现方式有很大的不同。这篇文章很旧,但仍然相关。

基本上,这在GHC中有描述,它详细说明了堆对象的格式,包括头和有效负载

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


这意味着,对于任何堆对象,大约都有一个字的开销。

因此,对象头(比如说像
data Foo=Foo{-#UNPACK}!Int String
)包含一个偏移量,指示非指针字的数量。对象头实际上只是一个指向具有这些调用的结构(实际上称为entry)的指针/清除/疏散功能,遵循一些特定于实现的数据。通用实现将包含长度/偏移量(尽管指针部分实际上是第一个),但是对于超级通用布局,您可能只需要让函数指针指向不需要查找此信息的专用版本。另请参见我链接的论文中的第7.1节。但该节(以及您的大部分答案)是关于函数如何实现的,而我的问题主要是关于普通值(如
Foo
),而不是函数/闭包。我认为这两者在实现上有所不同,因为对于像
Foo 1“Hi”
@theindigamer这样的普通值,您不需要
进入
/
清除
/
疏散
的函数,因为懒惰,它实际上是相同的;我做了一些修改,试图在我的回答中更清楚/明确地表达这一点。