国外数据和垃圾收集

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了国外数据和垃圾收集相关的知识,希望对你有一定的参考价值。

当我通过FFI分配一些数据并将终结器与它关联时,我在Haskell中获得了一个ForeignPtr。当此指针变为未引用时,GC会收集指针,从而导致终结器运行。但收集仅在GC运行且“不引用”不强制GC运行时发生。即可能会有很多指针,但由于指针本身不会占用太多内存,因此RTS根本没有看到启动GC的原因,因为根据我的investigations,RTS不会跟踪外部数据的大小。它是否正确?

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

答案

在运行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。固定数据的可能缺点是内存碎片和较慢的分配,但这也适用于(任何)返回稳定指针的外部分配。

另一答案

了解何时指针变为未引用并非易事。据我所知,无法执行您的请求,即通知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及其标记的STRefs一样工作,它们的设计是为了防止指针逃避它们的预期范围(如上所述)。这会利用rank-2类型,但是有效。

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

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

以上是关于国外数据和垃圾收集的主要内容,如果未能解决你的问题,请参考以下文章

Java 垃圾回收 - 收集算法

VS2015升级后的垃圾收集和Parallel.ForEach问题

Scala shell 中的垃圾收集

对“xxx”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。 错误解决一例。(代码片段

JVM垃圾回收器之G1(Garbage First)--new

JS高程4.变量,作用域和内存问题垃圾收集