[Haskell-cafe] help diagnosing space leak with IORef/STRef, just incrementing a million times.

Thomas Hartman thomashartman1 at gmail.com
Mon Jan 7 06:12:14 CET 2013


I have a space leak in a function that increments a number inside
IORef or STRef (either lazy or strict).

Is this the kind of problem that can be diagnosed and fixed using the
approach described in RWH, with space profiling? Otherwise what's the
right approach to diagnose and fix?

I wrote a non-list-using, and tail call-using, iterateMonadic funcation
that does the same thing as replicateM, in case the problem was due to
iterateM using a list structure, but iterateMonadic and replicateM had
same memory leak.

I can run this problem with +RTS -K100M -RTS but this aditional memory
shouldn't be needed.

{-# LANGUAGE RankNTypes, BangPatterns #-}

import Data.List
import Control.Monad.State.Strict
import Data.Array.MArray
import Data.Array.IO
import Data.Array.ST
import Control.Monad.ST
import Control.Applicative
import Data.IORef
import Data.STRef.Strict
import Data.STRef
import GHC.ST
import Control.Applicative ((<$>))

main = do
  -- putStrLn "ioIters, iterateMonadic: "
  -- print =<< ioIters iters iterateMonadic
  -- putStrLn "ioIters, replicateM_: "
  -- print =<< ioIters iters replicateM_

  -- putStrLn "lazySTIters, iterateMonadic: "
  -- print $ lazySTIters iters iterateMonadic
  -- putStrLn "lazySTIters, replicateM_: "
  -- print $ lazySTIters iters replicateM_

  putStrLn "strictSTIters, iterateMonadic: "
  print $ strictSTIters iters iterateMonadic
  -- putStrLn "strictSTIters, replicateM_: "
  -- print $ strictSTIters iters replicateM_


type Iter = (Monad m) => Int -> m () -> m ()

iterateMonadic :: (Monad m) => Int -> m a -> m a
iterateMonadic n mx = do
  let loop 0 acc = acc
      loop n acc = loop (n-1) (acc >> mx )
  loop n mx

iters = 10^7

ioIters :: Int -> Iter -> IO Int
ioIters numIters iteratorM = do
  tmp <- newIORef 0
  iteratorM numIters ( modifyIORef tmp (+1) )
  readIORef tmp

lazySTIters :: Int -> Iter -> Int
lazySTIters numIters iteratorM  = runST $ do
  tmp <- Data.STRef.newSTRef 0
  iteratorM numIters ( Data.STRef.modifySTRef tmp (+1) )
  Data.STRef.readSTRef tmp

strictSTIters :: Int -> Iter -> Int
strictSTIters numIters iteratorM = runST $ do
  tmp <- Data.STRef.Strict.newSTRef 0
  iteratorM numIters ( Data.STRef.Strict.modifySTRef tmp incr' )
  Data.STRef.Strict.readSTRef tmp

incr' (!x) = x + 1



More information about the Haskell-Cafe mailing list