The introduction
The following code shows that when using runhaskell
Haskell Garbage Collector releases the memory, when a
is no longer used. It results in core dump while releasing variable a
- for a purpose, to inspect the behaviour - a
has got nullFunPtr
as a finalizer.
module Main where import Foreign.Ptr import Foreign.ForeignPtr main :: IO () main = do a <- newForeignPtr nullFunPtr nullPtr putStrLn "Hello World"
The problem
When running the same in ghci it does not release memory. How can I force ghci to release no longer used variables?
$ ghci > import Foreign.Ptr > import Foreign.ForeignPtr > import System.Mem > a <- newForeignPtr nullFunPtr nullPtr > a <- return () -- rebinding variable a to show gc that I'm no longer using it > performGC > -- did not crash - GC didn't release memory > ^D Leaving GHCi. [1] 4396 segmentation fault (core dumped) ghci
Memory was released on exit, but this is too late for me. I'm extending GHCi and using it for other purpose and I need to release the memory earlier - on demand or as fast as possible would be really great.
I know that I can call finalizeForeignPtr
, but I'm using foreignPtr
just for debug purposes. How can I release a
in general in last example?
If there is no possibility to do it with ghci prompt, I can also modify ghci
code. Maybe I can release this a
by modyfing ghci Interactive Context or DynFlags? So far I've got no luck with my reaserch.
Haskell computations produce a lot of memory garbage - much more than conventional imperative languages. It's because data are immutable so the only way to store every next operation's result is to create new values. In particular, every iteration of a recursive computation creates a new value.
The Haskell runtime system employs a generational garbage collector (GC) with two generations 2. Generations are numbered starting with the youngest generation at zero.
Tracing through the code we find that the value is stored in the field closure_env
of the data type PersistentLinkerState
, which is a ClosureEnv
, i.e. a mapping from name to HValue
s. The relevant function in Linker.hs
is
extendLinkEnv :: [(Name,HValue)] -> IO () -- Automatically discards shadowed bindings extendLinkEnv new_bindings = modifyPLS_ $ \pls -> let new_closure_env = extendClosureEnv (closure_env pls) new_bindings in return pls{ closure_env = new_closure_env }
and although the comment indicates that it should remove the shadowed binding, it does not, at least not the way you want it to.
The reason is, as AndrewC writes correctly: Although both variables have the same source code name, they are different to the compiler (they have a different Unique
attached). We can observe this after adding some tracing to the function above:
*GHCiGC> a <- newForeignPtr nullFunPtr nullPtr extendLinkEnv [a_azp] *GHCiGC> a <- return () extendLinkEnv [a_aF0] *GHCiGC> performGC extendLinkEnv [it_aFL]
Removing bindings with the same source-name at this point should solve your GC problem, but I don’t know the compiler well enough to tell what else would break. I suggest you open a ticket, hopefully someone will know.
Confusion on binding vs. value
In the comments there seems to be some confusion about bindings and values. Consider this code:
> a <- return something > b <- return somethingelse > a <- return (b+b) > b <- return anewthing
With the current implementation, the heap will consist of `
something
somethingelse
(+)
operator and somethingelse
anewthing
.Furthermore the environment of the interpreter has references to all four heap values, so nothing can be GC’ed.
What remdezx rightly expected is that GHCi would drop the reference to something
and somethingelse
. This, in turn, would allow the run time system to garbage collect something
(we assume no further references). GHCi still references the thunk, which in turn references somethingelse
, so this would not be garbage collected.
Clearly the question was very implementation specific, and so is this answer :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With