第一个问题--行为低于预期是合乎逻辑的,还是应该向GHC报告一个bug?
下面的代码会泄漏内存(在ghc-8.8.4上测试),因为ghc似乎添加了join point,并在循环结束时跳转到它,从而构建了堆栈。
{-# OPTIONS_GHC -fno-full-laziness #-}
module Main where
import Control.Concurrent.Async (async,waitCatch)
import Data.IORef
import GHC.Conc
main :: IO ()
main = do
val <- newIORef 0 :: IO (IORef Int)
let loop1 = do
cval <- readIORef val
threadDelay 1
writeIORef val (cval + 1)
case cval > 100000000 of
True -> error "done"
False -> loop1
loop1 -- Deliberately, add this to cause space leak, but this statement is never executed because of case branching above
loop1Async <- async loop1
res <- waitCatch loop1Async
return ()使用-O2 -rtsopts -threaded编译并使用+RTS -s -hT -N运行会因为堆栈增长而导致空间泄漏。
查看核心输出,泄漏似乎是由于join (我猜它是一个join point)和循环末尾的跳转导致堆栈增长(如果我没有读错核心的话)。删除loop1中的最后一条语句可以修复泄漏。
ghc core输出为here。
更新:根据评论中的反馈,这似乎是符合逻辑的行为,而不是ghc中的错误。因此,有一个解释堆栈增加的答案是很好的。这有助于我们了解这里发生了什么。上面已经发布了ghc core输出。
发布于 2021-08-28 02:39:14
我当然希望这一行会导致堆栈空间的使用。对loop1的额外调用几乎是无关紧要的。
将测试常量更改为10,而不是更大的数字,并将return ()分支替换为print cval。
比较使用和不使用"never executed“语句得到的输出。您可能会发现它的执行程度比您想象的要高。
https://stackoverflow.com/questions/68960060
复制相似问题