It looks offhand like you're not being strict enough when you put
things back in the IORef, and so it's building up thunks of (+1)...
With two slight mods:
go 0 = return ()
go n = do modifyIORef ior (+1)
go (n-1)
-->
go 0 = return ()
go n = do modifyIORef ior (\ x -> let x' = x+1 in x `seq` x')
go (n-1)
and
go n = do x <- readIORef ior
writeIORef ior (x+1)
go (n-1)
-->
go n = do x <- readIORef ior
writeIORef ior $! x+1
go (n-1)
It runs much better (with loop count = 10,000,000) -- leak1 is the
code you posted, leak2 is with these changes:
r...@hugo:~$ ./leak1 +RTS -s
./leak1 +RTS -s
200,296,364 bytes allocated in the heap
365,950,896 bytes copied during GC
66,276,472 bytes maximum residency (7 sample(s))
1,906,448 bytes maximum slop
131 MB total memory in use (1 MB lost due to
fragmentation)
<snip>
%GC time 75.9% (79.2% elapsed)
Alloc rate 977,656,335 bytes per MUT second
Productivity 24.0% of total user, 20.5% of total elapsed
r...@hugo:~$ ./leak2 +RTS -s
./leak2 +RTS -s
160,006,032 bytes allocated in the heap
11,720 bytes copied during GC
1,452 bytes maximum residency (1 sample(s))
9,480 bytes maximum slop
1 MB total memory in use (0 MB lost due to
fragmentation)
<snip>
%GC time 0.5% (0.8% elapsed)
Alloc rate 626,590,037 bytes per MUT second
Productivity 99.2% of total user, 97.8% of total elapsed
-Ross
On Jun 18, 2009, at 10:46 PM, Jim Snow wrote:
I'm having some trouble with excessive memory use in a program that
uses a lot of IORefs. I was able to write a much simpler program
which exhibits the same sort of behavior. It appears that
"modifyIORef" and "writeIORef" leak memory; perhaps they keep a
reference to the old value. I tried both ghc-6.8.3 and ghc-6.10.1.
Is this a known limitation, or is this a ghc bug, or am I using
IORefs in the wrong way?
-jim
module Main where
import Data.IORef
import Control.Monad
-- Leaks memory
leakcheck1 ior =
do go 1000000000
where
go 0 = return ()
go n = do modifyIORef ior (+1)
go (n-1)
-- Leaks memory
leakcheck2 ior =
do go 1000000000
where
go 0 = return ()
go n = do x <- readIORef ior
writeIORef ior (x+1)
go (n-1)
-- Runs in constant memory
leakcheck3 ior =
do go 1000000000
where
go 0 = return ()
go n = do x <- readIORef ior
go (n-1)
main :: IO ()
main =
do ior <- newIORef 0
leakcheck2 ior
compiled with: ghc -O2 --make Leak.hs -o Leak
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe