
On Wed, Apr 14, 2010 at 2:13 PM, Gregory Collins
Jesper Louis Andersen
writes: This post describes some odd behaviour I have seen in GHC 6.12.1 when writing Combinatorrent. The post is literate Haskell so you can run it. The executive summary: A space leak occurs when a new process is spawned from inside another process - and I can't figure out why. I am asking for help on haskell-cafe.
...[snip]...
import Control.Monad.State
Does the problem go away if you use "Control.Monad.State.Strict"?
Nope :) That was the first thing I tried here. I tried playing with optimization level too. 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). The two versions I compared: Low memory: \begin{code}
startp4 :: IO ThreadId startp4 = spawn () () (return ())
startp3 :: IO ThreadId startp3 = spawn () () (forever $ do liftIO startp4 liftIO $ putStrLn "Delaying" liftIO $ threadDelay (3 * 1000000))
main1 = do putStrLn "Main thread starting" startp3 threadDelay (1 * 1000000)
main = main1 \end{code}
Too much memory: \begin{code}
startp4 :: IO ThreadId startp4 = spawn () () (forever $ return ())
startp3 :: IO ThreadId startp3 = spawn () () (forever $ do liftIO startp4 liftIO $ putStrLn "Delaying" liftIO $ threadDelay (3 * 1000000))
main1 = do putStrLn "Main thread starting" startp3 threadDelay (1 * 1000000)
main = main1 \end{code}
The difference is whether or not the threads must keep returning () or if they returns it once. 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: \begin{code}
startp4 :: IO ThreadId startp4 = spawn () () (liftIO $ threadDelay (100 * 1000000))
startp3 :: IO ThreadId startp3 = spawn () () (forever $ do liftIO startp4 liftIO $ putStrLn "Delaying" liftIO $ threadDelay (3 * 1000000))
main1 = do putStrLn "Main thread starting" startp3 threadDelay (1 * 1000000)
main = main1 \end{code}
It will be interesting to hear what fixes this! Jason