国外数据和垃圾收集

时间:2017-12-29 21:11:37

标签: haskell garbage-collection ffi

当我通过FFI分配一些数据并将终结器与它关联时,我在Haskell中得到attoptions。当此指针变为未引用时,GC会收集指针,从而导致终结器运行。但是收集只发生在GC运行和"未引用"不会强制GC运行。即可能会有很多指针,但由于指针本身并没有占用太多内存,因此RTS根本没有看到启动GC的原因,因为根据我的{{{},RTS不会跟踪外来数据的大小。 3}}。这是对的吗?

如何沟通"当此指针变为未引用时,立即收集它"到RTS?是否有任何标志可以控制何时启动GC?这是一个真正的程序的问题(因为任何真正的程序总是有足够的显式垃圾来刺激GC)?

2 个答案:

答案 0 :(得分:3)

在运行GC之前,RTS不知道是否有任何数据未被引用。 GHC没有引用计数GC,这将允许立即对垃圾采取行动。您可以尝试自己实施引用计数,或者使用System.Mem中的手动GC。

在Haskell-land中没有跟踪外部分配。如果您想要更多控制,但没有自定义GC或引用计数,则可以使用e。 G。 Foreign.Marhsal.Array用于手动/范围分配和解除分配。

另一种选择是在GHC RTS中使用固定分配。这为您提供了不被GC移动的内存。对固定数据的引用可以在没有开销的情况下传递给外部代码,但是跟踪固定数据,可以是GC-d,并且像通常的堆数据一样触发GC。 Here's针对固定数据的一个API。另一种选择只是ByteString。固定数据的可能缺点是内存碎片和较慢的分配,但这也适用于(任何)返回稳定指针的外部分配。

答案 1 :(得分:1)

了解指针何时变为未引用并非易事。 据我所知,无法执行您的请求,即通知GC现在无法再访问指针。最好的情况是,可以触发GC循环,但没有硬性保证。

根据您的描述,您可能更喜欢引用计数机制而不是垃圾收集。但是,特别是在复杂的纯代码中,很难识别计数器应该递增或递减的点:在基于状态或基于IO的monad中,如果这样的副作用被正确排序,则会更容易w.r.t.其余的计算。

如果你真的不需要超过" one"之类的引用计数,一种常见的习惯用法是使用with - 样式函数来处理分配和释放。 这可能有点难以正确处理。

例如,一个简单的实现可能是

-- very simplified code
withMyResource :: (ResourcePtr -> IO r) -> IO r
withMyResource action = do
   p <- allocResourcePtr
   result <- action p
   deallocResourcePtr p
   return result

然后可以将其用作

withResource $ \ptr -> do
   use ptr

请注意,这不是完全安全的,因为可能会返回指针,使其在释放后生效

ptr <- withResource return
use ptr -- dangerous!

正确的指针处理例程应该像ST monad及其标记的STRef一样工作,它们的设计是为了防止指针逃离预期的范围(如上所述)。这会利用rank-2类型,但是有效。

但是,人们可以忍受天真的with例程,并且小心不要让指针逃脱。

另一个不安全的问题是action能够抛出异常引起的。 (这可以使用bracket来处理 - 就像库中的例程一样。)