<br><br><div class="gmail_quote">On Wed, Apr 14, 2010 at 2:13 PM, Gregory Collins <span dir="ltr"><<a href="mailto:greg@gregorycollins.net">greg@gregorycollins.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="im">Jesper Louis Andersen <<a href="mailto:jesper.louis.andersen@gmail.com">jesper.louis.andersen@gmail.com</a>> writes:<br>
<br>
> This post describes some odd behaviour I have seen in GHC 6.12.1 when writing<br>
> Combinatorrent. The post is literate Haskell so you can run it. The executive<br>
> summary: A space leak occurs when a new process is spawned from inside another<br>
> process - and I can't figure out why. I am asking for help on haskell-cafe.<br>
><br>
</div>> ...[snip]...<br>
>><br>
>> import Control.Monad.State<br>
<br>
Does the problem go away if you use "Control.Monad.State.Strict"? <br></blockquote><div><br>Nope :) That was the first thing I tried here.<br><br>I tried playing with optimization level too.<br><br>Next I tried making two versions that were as similar as possible and then comparing the core with ghc-core. I can't see a difference between a version that uses 1MB and a version that uses 160MB (on my system 160MB is the worst I can get it to blow up).<br>
<br>The two versions I compared:<br>Low memory:<br>\begin{code}<br>> startp4 :: IO ThreadId<br>> startp4 = spawn () () (return ())<br><br>> startp3 :: IO ThreadId<br>> startp3 = spawn () () (forever $<br>> do liftIO startp4<br>
> liftIO $ putStrLn "Delaying"<br>> liftIO $ threadDelay (3 * 1000000))<br><br>> main1 = do<br>> putStrLn "Main thread starting"<br>> startp3<br>
> threadDelay (1 * 1000000)<br>><br>> main = main1<br>\end{code}<br><br>Too much memory:<br>\begin{code}<br>> startp4 :: IO ThreadId<br>> startp4 = spawn () () (forever $ return ())<br><br>> startp3 :: IO ThreadId<br>
> startp3 = spawn () () (forever $<br>> do liftIO startp4<br>> liftIO $ putStrLn "Delaying"<br>> liftIO $ threadDelay (3 * 1000000))<br>
<br>> main1 = do<br>> putStrLn "Main thread starting"<br>> startp3<br>> threadDelay (1 * 1000000)<br>><br>> main = main1<br>\end{code}<br><br>The difference is whether or not the threads must keep returning () or if they returns it once.<br>
<br>I'm not sure what to make of it. My conclusion is that keeping the thread alive via forever is the problem, but when I test this hypothesis with a threadDelay the space leak goes away:<br><br>\begin{code}<br>> startp4 :: IO ThreadId<br>
> startp4 = spawn () () (liftIO $ threadDelay (100 * 1000000))<br><br>> startp3 :: IO ThreadId<br>> startp3 = spawn () () (forever $<br>> do liftIO startp4<br>> liftIO $ putStrLn "Delaying"<br>
> liftIO $ threadDelay (3 * 1000000))<br><br>> main1 = do<br>> putStrLn "Main thread starting"<br>> startp3<br>> threadDelay (1 * 1000000)<br>><br>> main = main1<br>
\end{code}<br><br>It will be interesting to hear what fixes this!<br><br>Jason<br></div></div>