Given the program:
import Language.Haskell.Exts.Annotated -- from haskell-src-exts
import System.Mem
import System.IO
import Control.Exception
main :: IO ()
main = do
evaluate $ length $ show $ fromParseResult $ parseFileContents $ "data C = C {a :: F {- " ++ replicate 400000 'd' ++ " -} }"
performGC
performGC
performGC
Using GHC 7.0.3, when I run:
$ ghc --make Temp.hs -rtsopts && Temp.exe +RTS -G1 -S
Alloc Copied Live GC GC TOT TOT Page Flts
bytes bytes bytes user elap user elap
...
29463264 64 8380480 0.00 0.00 0.64 0.85 0 0 (Gen: 0)
20 56 8380472 0.00 0.00 0.64 0.86 0 0 (Gen: 0)
0 56 8380472 0.00 0.00 0.64 0.87 0 0 (Gen: 0)
42256 780 33452 0.00 0.00 0.64 0.88 0 0 (Gen: 0)
0 0.00 0.00
The performGC
call seems to leave 8Mb of memory live, even though it seems like all the memory should be dead. How come?
(Without -G1
I see 10Mb live at the end, which I also can't explain.)
Here's what I see (after inserting a
print
before the lastperformGC
, to help tag when things happen.So after GCs there is still 1M on the heap (without -G1). With -G1 I see:
So about 2M. This is on x86_64/Linux.
Let's think about the STG machine storage model to see if there's something else on the heap.
Things that could be in that 1M of space:
[]
, string constants, and the smallInt
andChar
pool, plus things in libraries, thestdin
MVar?main
thread.From experience, this figure of slightly less than 1M seems to be the default "footprint" of a GHC binary. That's about what I've seen in other programs as well (e.g. shootout program smallest footprints are never less than 900K).
Perhaps the profiler can say something. Here's the
-hT
profile (no profiling libs needed), after I insert a minimal busy loop at the end to string out the tail:Results in this graph:
Victory! Look at that ~1M thread stack object sitting there!
I don't know of a way to make TSOs smaller.
The code that produced the above graph:
Compiling the code with
-O -ddump-simpl
, I see the following global definition in the simplifier output:The input to the parser function has become a global string constant. Globals are never garbage collected in GHC, so that's probably what's occupying the 8MB of memory after garbage colleciton.