[Haskell-cafe] GHC, odd concurrency space leak

Jason Dagit dagit at codersbase.com
Wed Apr 14 17:49:43 EDT 2010


On Wed, Apr 14, 2010 at 2:44 PM, Jason Dagit <dagit at codersbase.com> wrote:

>
>
> On Wed, Apr 14, 2010 at 2:13 PM, Gregory Collins <greg at gregorycollins.net>wrote:
>
>> Jesper Louis Andersen <jesper.louis.andersen at gmail.com> 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!
>

> forever' m = do _ <- m
>                 forever' m

When I define that version of forever, the space leak goes away.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20100414/42747fba/attachment.html


More information about the Haskell-Cafe mailing list