我有8 GB的RAM,但是Haskell程序似乎只能使用1.3 GB。
我正在使用这个简单的程序来确定GHC程序可以分配多少内存:
import System.Environment
import Data.Set as Set
main = do
args <- getArgs
let n = (read $ args !! 0) :: Int
s = Set.fromList [0..n]
do
putStrLn $ "min: " ++ (show $ findMin s)
putStrLn $ "max: " ++ (show $ findMax s)
这是我所发现的:
运行
./mem.exe 40000000 +RTS -s
的1113 MB total memory in use
./mem.exe 42000000 +RTS -s
失败,显示out of memory error
./mem.exe 42000000 +RTS -s -M4G
运行-M4G: size outside allowed range
错误./mem.exe 42000000 +RTS -s -M3.9G
的out of memory error
通过Windows任务管理器监视该过程显示最大内存使用量约为1.2 GB。
我的系统:Win7、8 GB RAM,Haskell平台2011.04.0.0,ghc 7.0.4。
我正在使用:
ghc -O2 mem.hs -rtsopts
如何利用所有可用的RAM?我缺少明显的东西吗?
最佳答案
当前,在Windows上,GHC是32位GHC-我认为Windows 7.6应当可以使用Windows的64位GHC。
其结果之一是,在Windows上,您不能使用超过4G - 1BLOCK
的内存,因为允许作为大小参数的最大值为HS_WORD_MAX
:
decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX) / BLOCK_SIZE;
使用32位字
HS_WORD_MAX = 2^32-1
。那解释了
因为
decodeSize()
将4G
解码为2^32
。升级GHC后,此限制也将保留,直到最终发布适用于Windows的64位GHC。
作为32位进程,用户模式虚拟地址空间被限制为2或4 GB(取决于
IMAGE_FILE_LARGE_ADDRESS_AWARE
标志的状态),请参见Memory limits for Windows Releases。现在,您正在尝试构造一个包含4200万个4字节
Set
的Int
。 Data.Set.Set
每个元素(构造函数,大小,左右子树指针,元素指针)的开销为5个字,因此Set
将占用约0.94 GiB的内存(1.008'metric'GB)。但是该进程使用的内存大约是它的两倍或更多(它需要用于垃圾收集的空间,至少是事件堆的大小)。在我的64位linux上运行该程序,输入21000000(以弥补
Int
和指针的两倍大),我得到了$ ./mem +RTS -s -RTS 21000000
min: 0
max: 21000000
31,330,814,200 bytes allocated in the heap
4,708,535,032 bytes copied during GC
1,157,426,280 bytes maximum residency (12 sample(s))
13,669,312 bytes maximum slop
2261 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 59971 colls, 0 par 2.73s 2.73s 0.0000s 0.0003s
Gen 1 12 colls, 0 par 3.31s 10.38s 0.8654s 8.8131s
INIT time 0.00s ( 0.00s elapsed)
MUT time 12.12s ( 13.33s elapsed)
GC time 6.03s ( 13.12s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 18.15s ( 26.45s elapsed)
%GC time 33.2% (49.6% elapsed)
Alloc rate 2,584,429,494 bytes per MUT second
Productivity 66.8% of total user, 45.8% of total elapsed
但是
top
仅报告内存使用情况的1.1g
-top
(可能是任务管理器)仅报告事件堆。因此,似乎未设置
IMAGE_FILE_LARGE_ADDRESS_AWARE
,您的进程被限制为2GB的地址空间,而4,200万个Set
需要的空间更多-除非您指定最大或建议的堆大小较小:$ ./mem +RTS -s -M1800M -RTS 21000000
min: 0
max: 21000000
31,330,814,200 bytes allocated in the heap
3,551,201,872 bytes copied during GC
1,157,426,280 bytes maximum residency (12 sample(s))
13,669,312 bytes maximum slop
1154 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 59971 colls, 0 par 2.70s 2.70s 0.0000s 0.0002s
Gen 1 12 colls, 0 par 4.23s 4.85s 0.4043s 3.3144s
INIT time 0.00s ( 0.00s elapsed)
MUT time 11.99s ( 12.00s elapsed)
GC time 6.93s ( 7.55s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 18.93s ( 19.56s elapsed)
%GC time 36.6% (38.6% elapsed)
Alloc rate 2,611,793,025 bytes per MUT second
Productivity 63.4% of total user, 61.3% of total elapsed
将最大堆大小设置为低于自然使用的大小,实际上使它的容纳空间几乎不超过
Set
所需的空间,而这会花费更长的GC时间,并且建议使用-H1800M
的堆大小可以使其仅使用结束1831 MB total memory in use (0 MB lost due to fragmentation)
因此,如果您指定的最大堆大小低于2GB(但足以容纳
Set
),则应该可以使用。