我正在处理Haskell程序中的内存泄漏,并且能够将其隔离为处理数组时非常基本的惰性问题。我了解那里发生了什么。数组的第一个元素被计算,其余的则产生延迟的计算,这消耗了堆。不幸的是,我无法对整个数组计算强制严格。
我尝试了seq,BangPatterns,($!)的各种组合,但没有成功。
import Control.Monad
force x = x `seq` x
loop :: [Int] -> IO ()
loop x = do
when (head x `mod` 10000000 == 0) $ print x
let x' = force $ map (+1) x
loop x'
main = loop $ replicate 200 1
具有标准配置文件选项的配置文件并没有提供我所知道的更多信息:
ghc -prof -fprof-auto-calls -rtsopts test.hs
./test +RTS -M300M -p -hc
这将在几秒钟内耗尽内存。
答案 0 :(得分:6)
force x = x `seq` x
那没用。 seq
并不意味着“立即评估”。意思是“在返回正确的事物的结果之前先评估左边的事物”。当它们相同时,它什么也不做,并且您的force
等效于id
。尝试以下方法:
import Control.DeepSeq
import Control.Monad
loop :: [Int] -> IO ()
loop x = do
when (head x `mod` 10000000 == 0) $ print x
let x' = map (+1) x
loop $!! x'
main = loop $ replicate 200 1
这将评估x'
及其在loop x'
之前的所有内容,这很有用。
或者,Control.DeepSeq具有一个有用的force
函数。在这种情况下,它的语义是“在返回评估结果之前,先评估列表中的所有元素”。如果您使用其force
函数代替自己的函数,则原始代码将可以正常工作,因为loop
的第一行确实会评估列表的开头。