Haskell中的垃圾回收和并行计算

13

大多数编程语言使用垃圾回收器(可能所有编程语言),与并行计算有关的一个主要问题是: 垃圾回收器必须停止所有正在运行的线程以删除未使用的对象。Haskell也有垃圾回收器。但由于其纯度性质,Haskell保证没有任何计算会改变原始数据,而是生成一个副本,然后进行更改。我想,这样GC就不必停止所有线程来完成其工作。我只是好奇:Haskell是否存在相同的垃圾回收问题?


4
Haskell具有可变数据。毕竟它是“世界上最好的命令式编程语言”。只是它没有得到广泛认可和使用。此外,运行时系统可能需要同步才能运行GC,并且即使在Haskell中,该部分也肯定是不纯的。 - user395760
5
由于 Haskell 具有惰性求值的特点,即当一个 thunk 被重写为其代表的值时,实际上通常会发生很多更新。 - augustss
2个回答

19

GHC的垃圾回收器是并行而不是并发。这意味着它可以使用所有线程执行垃圾回收,但必须停止所有线程才能执行。并发垃圾收集实现起来要困难得多(通常也有更大的性能开销)。

有些讽刺的是,Haskell确实使用了许多可变对象,即thunks(未评估表达式)。可变对象不能自由地复制(对于不可变对象,过多的复制也应该受到限制)。

对于在多个核心上运行的程序,拥有真正的并发收集器会很好,但您也可以通过执行堆本地垃圾回收来获得不错的效果。其思想是仅由拥有数据的CPU收集未与多个CPU共享的数据。这通常适用于短暂的数据。Simons最近在这个领域做了一些工作。请参见他们的论文“Multicore Garbage Collection with Local Heaps”(PDF)。该论文还展示了一些类似于您提出的利用不变性的方法。

编辑:我忘记提到Erlang基本上就是您提出的方法。每个Erlang进程都有自己的堆,发送消息会将数据从一个进程复制到另一个进程中。因此,每个Erlang进程可以独立于所有其他进程执行其自己的GC。(缺点是Erlang不能给您提供共享内存并发。)


nominolo,感谢你详尽的回答。Simons的研究链接也很有价值,我会很快阅读它。 - Dmitry Bespalov

2
一些Seval GC的实现可以在不“停止世界”的情况下并行运行,就像你所建议的那样(我认为最新的Oracle JVM不会停止世界并支持多线程,例如;而大多数JVM都不是“停止世界”的)。请记住,不同语言实现的GC实现可能差别很大。有关GC的文献非常丰富,还有很多关于并行垃圾回收的研究论文。可以从一本好书开始,比如 the GC handbook(作者:Richard Jones、Antony Hosking、Eliot Moss),或至少看看维基百科Garbage Collection页面。纯函数语言(如Haskell)在很大程度上依赖于性能非常高的GC。其他语言有不同的限制(例如,Haskell相对于Java更少关注写障碍,但Haskell程序可能比Java分配更多内存)。对于并行GC,魔鬼就在于细节。

7
请注意,在GC研究(以及其他一些领域)中,“concurrent”和“parallel”这两个术语并不可以互换使用。Concurrent表示当用户线程正在运行时,GC可以同时进行;Parallel则表示多个GC线程可以同时工作,但是没有用户线程可以同时运行。我认为Hotspot虚拟机并没有真正的concurrent GC,它有各种大多数并发GC来同时执行部分GC工作(扫描),然后有一个较短的停顿时间(可能是parallel)。 - nominolo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接