给定程序:
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的内存保持 Activity 状态,即使所有内存似乎都已耗尽。怎么会?(没有
-G1
,我看到的是10Mb的结尾,这我也无法解释。) 最佳答案
这是我所看到的(在最后一个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)