鉴于该计划:
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
使用GHC 7.0.3,当我运行时:
$ 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
performGC
调用似乎会留下8Mb的内存,即使看起来所有内存都应该已经死了。怎么样?
(没有-G1
我最后看到10Mb直播,我也无法解释。)
答案 0 :(得分:18)
以下是我看到的内容(在最后print
之前插入performGC
之后),以帮助标记发生的事情。
524288 524296 32381000 0.00 0.00 1.15 1.95 0 0 (Gen: 0)
524288 524296 31856824 0.00 0.00 1.16 1.96 0 0 (Gen: 0)
368248 808 1032992 0.00 0.02 1.16 1.99 0 0 (Gen: 1)
0 808 1032992 0.00 0.00 1.16 1.99 0 0 (Gen: 1)
"performed!"
39464 2200 1058952 0.00 0.00 1.16 1.99 0 0 (Gen: 1)
22264 1560 1075992 0.00 0.00 1.16 2.00 0 0 (Gen: 0)
0 0.00 0.00
所以在GC之后,堆上仍然有1M(没有-G1)。使用-G1,我看到了:
34340656 20520040 20524800 0.10 0.12 0.76 0.85 0 0 (Gen: 0)
41697072 24917800 24922560 0.12 0.14 0.91 1.01 0 0 (Gen: 0)
70790776 800 2081568 0.00 0.02 1.04 1.20 0 0 (Gen: 0)
0 800 2081568 0.00 0.00 1.04 1.20 0 0 (Gen: 0)
"performed!"
39464 2184 1058952 0.00 0.00 1.05 1.21 0 0 (Gen: 0)
22264 2856 43784 0.00 0.00 1.05 1.21 0 0 (Gen: 0)
0 0.00 0.00
所以大约2M。这是在x86_64 / Linux上。
让我们考虑the STG machine storage model来查看堆上是否有其他内容。
可能存在于1M的空间中的事情:
[]
,字符串常量,小型Int
和Char
池,以及库中的stdin
MVar?main
主题。 根据经验,这个略低于1M的数字似乎是GHC二进制文件的默认“足迹”。这也是我在其他节目中看到的内容(例如,枪战计划最小的足迹永远不会少于900K)。
也许分析者可以说些什么。这是-hT
配置文件(不需要配置文件库),我在最后插入一个最小的忙循环来串出尾部:
$ ./A +RTS -K10M -S -hT -i0.001
此图表中的结果:
胜利!看看坐在那里的~1M线程堆栈对象!
我不知道如何缩小TSO。
产生上图的代码:
import Language.Haskell.Exts.Annotated -- from haskell-src-exts
import System.Mem
import System.IO
import Data.Int
import Control.Exception
main :: IO ()
main = do
evaluate $ length $ show $ fromParseResult
$ parseFileContents
$ "data C = C {a :: F {- " ++ replicate 400000 'd' ++ " -} }"
performGC
performGC
print "performed!"
performGC
-- busy loop so we can sample what's left on the heap.
let go :: Int32 -> IO ()
go 0 = return ()
go n = go $! n-1
go (maxBound :: Int32)
答案 1 :(得分:1)
使用-O -ddump-simpl
编译代码,我在简化器输出中看到以下全局定义:
lvl2_r12F :: [GHC.Types.Char]
[GblId]
lvl2_r12F =
GHC.Base.unpackAppendCString# "data C = C {a :: F {- " lvl1_r12D
解析器函数的输入已成为全局字符串常量。 Globals永远不会在GHC中被垃圾收集,所以这可能是垃圾收集后占用8MB内存的原因。