[GHC] #12889: memory leak

#12889: memory leak -------------------------------------+------------------------------------- Reporter: zoranbosnjak | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- This simple test program leaks memory for no obvious reason. {{{#!hs module Main where import Control.Monad import Control.Monad.Trans.Reader main :: IO () main = do runReaderT task () main task :: ReaderT () IO () task = forM_ [(1::Integer)..] $ \cnt -> do return cnt }}} However, there are some minor changes that (each individual change alone) make this program run in constant memory. 1. If I remove {{{#!hs module Main where }}} 2. If I remove recursive call to main 3. If I put task definition under the scope of main, like so {{{#!hs module Main where import Control.Monad import Control.Monad.Trans.Reader main :: IO () main = do runReaderT task () main where task :: ReaderT () IO () task = forM_ [(1::Integer)..] $ \cnt -> do return cnt }}} Any of the changes above make the program run OK, but I belive that this should be also true for the original test program. I am not sure where the problem is (if at all), but it's extremely difficult to isolate this kind of problem in the real application. Please check if anything can be done on the compiler or runtime to prevent this kind of problems. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12889 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#12889: memory leak -------------------------------------+------------------------------------- Reporter: zoranbosnjak | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: invalid | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by rwbarton): * status: new => closed * resolution: => invalid Comment: Your program is retaining the evaluated list `[1,2,3,...]` which grows forever. You might say this is dumb, and in this case it is. But, if you had written {{{#!hs task = forM_ (filter expensiveTest [(1::Integer)..10000000]) $ \cnt -> do ... }}} then you might well have filed a bug wondering why your program is recalculating the list `filter expensiveTest [(1::Integer)..10000000]` for every call to `task`, whenever you make any of your changes 1, 2, 3. So, there is a real tension here. The normal behavior is to calculate a given expression once per time that its surrounding function is entered. Here there is no function around `[(1::Integer)..]` at all, so we calculate it just once during the lifetime of the program. If you remove the recursive call to `main` then the value is also used just once, so it can be GCed as it is generated, but normally this will lead to a space leak. The reason that the other changes cause `task` to be recalculated are more obscure, and probably not very interesting. If you want to tell GHC to always recalculate `task`, it's better to introduce an explicit function, like {{{#!hs task :: () -> ReaderT () IO () task () = forM_ [(1::Integer)..] $ \cnt -> do ... }}} (Even then GHC might decide to share the computation of `[(1::Integer)..]`, but then you have a different issue.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12889#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC