【问题标题】:Making use of all available RAM in a Haskell program?在 Haskell 程序中使用所有可用的 RAM?
【发布时间】:2012-05-24 18:12:08
【问题描述】:

我有 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 Platform 2011.04.0.0、ghc 7.0.4。

我正在编译:ghc -O2 mem.hs -rtsopts

如何利用所有可用的 RAM?我错过了什么明显的东西吗?

【问题讨论】:

  • 请升级到更新版本的 GHC。您是否在 Windows 机器上设置了最大进程限制? GHC 没有堆限制,因此操作系统可能会限制您的进程地址空间。
  • 如果您不想离开使用 Haskell 平台的舒适区,请注意下一个版本将于本月发布;上次我检查它是否包含 GHC 7.4.1。

标签: windows haskell memory-management ghc heap-memory


【解决方案1】:

目前,在 Windows 上,GHC 是 32 位 GHC - 我认为 Windows 的 64 位 GHC 应该在 7.6 到来时可用。

这样做的一个结果是,在 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

这就解释了

running ./mem.exe 42000000 +RTS -s -M4G 使用 -M4G 出错:大小超出允许范围

因为decodeSize()4G 解码为2^32

在升级您的 GHC 后,此限制仍然存在,直到最终发布适用于 Windows 的 64 位 GHC。

作为 32 位进程,用户模式虚拟地址空间限制为 2 或 4 GB(取决于IMAGE_FILE_LARGE_ADDRESS_AWARE 标志的状态),参见Memory limits for Windows Releases

现在,您正在尝试构建一个包含 4200 万个 4 字节 Ints 的 SetData.Set.Set 每个元素有五个字的开销(构造函数、大小、左右子树指针、指向元素的指针),因此 Set 将占用大约 0.94 GiB 的内存(1.008“公制”GB)。但是该进程使用了​​大约两倍或更多(它需要用于垃圾收集的空间,至少是活动堆的大小)。

在我的 64 位 linux 上运行程序,输入 21000000(以弥补两倍大的 Ints 和指针),我得到

$ ./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 的地址空间,而4200 万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 时间稍长,建议堆大小为@987654343 @ 让它只使用完成

1831 MB total memory in use (0 MB lost due to fragmentation)

因此,如果您指定的最大堆大小低于 2GB(但足够大以容纳 Set),它应该可以工作。

【讨论】:

  • 而且,它是否与 -M1800M 一起运行?
  • 太棒了。如果你设置IMAGE_FILE_LARGE_ADDRESS_AWARE(默认清除),你应该可以使用4GB。
【解决方案2】:

default heap size is unlimited

在 64 位 Windows XP 机器上使用 GHC 7.2,我可以通过显式设置更大的堆大小来分配更高的值:

$ ./A 42000000  +RTS -s -H1.6G
min: 0
max: 42000000
  32,590,763,756 bytes allocated in the heap
   3,347,044,008 bytes copied during GC
     714,186,476 bytes maximum residency (4 sample(s))
       3,285,676 bytes maximum slop
            1651 MB total memory in use (0 MB lost due to fragmentation)

$ ./A 42000000  +RTS -s -H1.7G
min: 0
max: 42000000
  32,590,763,756 bytes allocated in the heap
   3,399,477,240 bytes copied during GC
     757,603,572 bytes maximum residency (4 sample(s))
       3,281,580 bytes maximum slop
            1754 MB total memory in use (0 MB lost due to fragmentation)

甚至:

$ ./A 42000000  +RTS -s -H1.85G
min: 0
max: 42000000
  32,590,763,784 bytes allocated in the heap
   3,492,115,128 bytes copied during GC
     821,240,344 bytes maximum residency (4 sample(s))
       3,285,676 bytes maximum slop
            1909 MB total memory in use (0 MB lost due to fragmentation)

也就是说,我最多可以分配到Windows XP 2G process limit。我想在 Win 7 上你不会有这么低的限制——这张表suggests either 4G or 192G——只要你需要多少就要求多少(并使用更新的 GHC)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-19
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 2019-07-24
    • 2022-01-24
    • 1970-01-01
    相关资源
    最近更新 更多