简介
以下代码显示当使用runhaskell
Haskell垃圾收集器释放内存时,不再使用a
时。它会在释放变量a
时导致核心转储 - 出于某种目的,检查行为 - a
已将nullFunPtr
作为终结器。
module Main where
import Foreign.Ptr
import Foreign.ForeignPtr
main :: IO ()
main = do
a <- newForeignPtr nullFunPtr nullPtr
putStrLn "Hello World"
问题
在ghci中运行相同时,它不会释放内存。如何强制ghci释放不再使用的变量?
$ ghci
> import Foreign.Ptr
> import Foreign.ForeignPtr
> import System.Mem
> a <- newForeignPtr nullFunPtr nullPtr
> a <- return () -- rebinding variable a to show gc that I'm no longer using it
> performGC
> -- did not crash - GC didn't release memory
> ^D
Leaving GHCi.
[1] 4396 segmentation fault (core dumped) ghci
内存在退出时被释放,但对我来说已经太晚了。我正在扩展GHCi并将其用于其他目的,我需要提前释放内存 - 按需或尽可能快地发布内存。
我知道我可以调用finalizeForeignPtr
,但我只是出于调试目的使用foreignPtr
。如何在上一个示例中一般发布a
?
如果没有可能使用ghci提示,我也可以修改ghci
代码。也许我可以通过modyfing ghci Interactive Context或DynFlags发布这个a
?到目前为止,我的研究工作没有运气。
答案 0 :(得分:9)
跟踪代码,我们发现该值存储在数据类型closure_env
的字段PersistentLinkerState
中,即ClosureEnv
,即从名称到{{1}的映射}}秒。 HValue
中的相关功能是
Linker.hs
虽然评论表明它应该删除阴影绑定,但它不会,至少不是你想要它的方式。
原因是,正如AndrewC正确写道:尽管两个变量都具有相同的源代码名称,但它们与编译器不同(它们附加了不同的extendLinkEnv :: [(Name,HValue)] -> IO ()
-- Automatically discards shadowed bindings
extendLinkEnv new_bindings =
modifyPLS_ $ \pls ->
let new_closure_env = extendClosureEnv (closure_env pls) new_bindings
in return pls{ closure_env = new_closure_env }
)。我们可以在上面的函数中添加一些跟踪后观察到这一点:
Unique
此时删除具有相同源名称的绑定应解决您的GC问题,但我不太了解编译器,以告诉其他什么会破坏。我建议你打开一张票,希望有人知道。
对绑定与价值的混淆
在评论中,似乎有一些关于绑定和值的混淆。请考虑以下代码:
*GHCiGC> a <- newForeignPtr nullFunPtr nullPtr
extendLinkEnv [a_azp]
*GHCiGC> a <- return ()
extendLinkEnv [a_aF0]
*GHCiGC> performGC
extendLinkEnv [it_aFL]
使用当前实现,堆将由`
组成> a <- return something
> b <- return somethingelse
> a <- return (b+b)
> b <- return anewthing
something
somethingelse
运算符和(+)
somethingelse
。此外,解释器的环境引用了所有四个堆值,因此没有任何内容可以用于GC。
remdezx正确地期望GHCi会将引用放到anewthing
和something
。反过来,这将允许运行时系统进行垃圾收集somethingelse
(我们假设没有进一步的引用)。 GHCi仍然引用thunk,而thunk又引用something
,所以这将不被垃圾收集。
显然,这个问题非常具体,所以答案是: - )