【发布时间】:2014-07-27 22:32:05
【问题描述】:
考虑以下程序。它永远运行,没有任何用处,但 ghci 中的内存消耗是恒定的:
--NoExplode.hs
module Main (main) where
test :: [Int] -> IO()
test lst = do
print "test"
rList lst
rList :: [Int] -> IO ()
rList [] = return ()
rList (x:xs) = do
rList xs
main = do
test [1..]
现在考虑以下对上述内容的简单修改版本。当这个程序在 ghci 中运行时,内存会爆炸。唯一的区别是print "test" 现在分配给test 的do 块中的x。
--Explode.hs
module Main (main) where
test :: [Int] -> IO()
test lst = do
x <- print "test"
rList lst
rList :: [Int] -> IO ()
rList [] = return ()
rList (x:xs) = do
rList xs
main = do
test [1..]
为什么将 print "test" 更改为 x <- print "test" 会导致 ghci 崩溃?
附言我在尝试理解Memory exploding upon writing a lazy bytestring to file in ghci 时遇到了这个问题,而那里的问题(我认为)基本上归结为上述问题。谢谢
【问题讨论】:
-
在我看来,这显然是 GHCi 中的一个错误。有趣的是,即使您使用优化编译模块然后将编译后的代码加载到 GHCi 中,这也会体现在 GHCi 中。如果您只编译它并在没有 GHCi 的情况下运行它,即使没有优化,它也可以正常工作。因此,GHCi 中的某些东西似乎在维护对列表头部的引用,这在模块之外甚至不可见。
-
对于那些真正想在 GHCi 中运行代码的人,请注意安全并以有限的堆 (
ghci +RTS -M100m --RTS …) 运行 GHCi。 -
鉴于 ghc 将
[1..]浮动到顶级常量(Zeta 的答案中显示的核心中的lst_rq4),编译程序和在 ghci 中运行程序之间的行为差异并不奇怪.毕竟main引用了lst_rq4并且导出了main,确实可以在ghci 中输入main,然后按Ctrl-C 并再次输入main,它会重用lst_rq4的计算。
标签: haskell memory-leaks ghci