Haskell:ST/GC泄漏的内存没有收集?

NBF*_*RTW 6 garbage-collection haskell out-of-memory ghc

我在ST内部有一个计算,它通过Data.Vector.Unboxed.Mutable分配内存.永远不会读取或写入向量,也不会在runST之外保留任何引用(据我所知).我遇到的问题是,当我多次运行ST计算时,我有时似乎会保留向量的内存.

分配统计:

5,435,386,768 bytes allocated in the heap
    5,313,968 bytes copied during GC
  134,364,780 bytes maximum residency (14 sample(s))
    3,160,340 bytes maximum slop
          518 MB total memory in use (0 MB lost due to fragmentation)
Run Code Online (Sandbox Code Playgroud)

在这里,我将runST 20x调用为计算的不同值和128MB向量(再次 - 未使用,未返回或在ST之外引用).最大居住率看起来不错,基本上只是我的矢量加上几MB的其他东西.但总内存使用量表明我有四个同时激活的向量副本.这与矢量的大小完美匹配,对于256MB,我们按预期获得1030MB.

使用1GB向量耗尽内存(4x1GB +开销> 32位).我不明白为什么RTS保持看似未使用的,未引用的内存而不仅仅是GC,至少在分配会失败的时候.

使用+ RTS -S运行会显示以下内容:

    Alloc    Copied     Live    GC    GC     TOT     TOT  Page Flts
    bytes     bytes     bytes  user  elap    user    elap
134940616     13056 134353540  0.00  0.00    0.09    0.19    0    0  (Gen:  1)
   583416      6756 134347504  0.00  0.00    0.09    0.19    0    0  (Gen:  0)
   518020     17396 134349640  0.00  0.00    0.09    0.19    0    0  (Gen:  1)
   521104     13032 134359988  0.00  0.00    0.09    0.19    0    0  (Gen:  0)
   520972      1344 134360752  0.00  0.00    0.09    0.19    0    0  (Gen:  0)
   521100       828 134360684  0.00  0.00    0.10    0.19    0    0  (Gen:  0)
   520812       592 134360528  0.00  0.00    0.10    0.19    0    0  (Gen:  0)
   520936      1344 134361324  0.00  0.00    0.10    0.19    0    0  (Gen:  0)
   520788      1480 134361476  0.00  0.00    0.10    0.20    0    0  (Gen:  0)
134438548      5964 268673908  0.00  0.00    0.19    0.38    0    0  (Gen:  0)
   586300      3084 268667168  0.00  0.00    0.19    0.38    0    0  (Gen:  0)
   517840       952 268666340  0.00  0.00    0.19    0.38    0    0  (Gen:  0)
   520920       544 268666164  0.00  0.00    0.19    0.38    0    0  (Gen:  0)
   520780       428 268666048  0.00  0.00    0.19    0.38    0    0  (Gen:  0)
   520820      2908 268668524  0.00  0.00    0.19    0.38    0    0  (Gen:  0)
   520732      1788 268668636  0.00  0.00    0.19    0.39    0    0  (Gen:  0)
   521076       564 268668492  0.00  0.00    0.19    0.39    0    0  (Gen:  0)
   520532       712 268668640  0.00  0.00    0.19    0.39    0    0  (Gen:  0)
   520764       956 268668884  0.00  0.00    0.19    0.39    0    0  (Gen:  0)
   520816       420 268668348  0.00  0.00    0.20    0.39    0    0  (Gen:  0)
   520948      1332 268669260  0.00  0.00    0.20    0.39    0    0  (Gen:  0)
   520784       616 268668544  0.00  0.00    0.20    0.39    0    0  (Gen:  0)
   521416       836 268668764  0.00  0.00    0.20    0.39    0    0  (Gen:  0)
   520488      1240 268669168  0.00  0.00    0.20    0.40    0    0  (Gen:  0)
   520824      1608 268669536  0.00  0.00    0.20    0.40    0    0  (Gen:  0)
   520688      1276 268669204  0.00  0.00    0.20    0.40    0    0  (Gen:  0)
   520252      1332 268669260  0.00  0.00    0.20    0.40    0    0  (Gen:  0)
   520672      1000 268668928  0.00  0.00    0.20    0.40    0    0  (Gen:  0)
134553500      5640 402973292  0.00  0.00    0.29    0.58    0    0  (Gen:  0)
   586776      2644 402966160  0.00  0.00    0.29    0.58    0    0  (Gen:  0)
   518064     26784 134342772  0.00  0.00    0.29    0.58    0    0  (Gen:  1)
   520828      3120 134343528  0.00  0.00    0.29    0.59    0    0  (Gen:  0)
   521108       756 134342668  0.00  0.00    0.30    0.59    0    0  (Gen:  0)
Run Code Online (Sandbox Code Playgroud)

在这里,似乎我们的'活字节'超过~128MB.

+RTS -hy配置文件基本上只是说我们分配128MB:

http://imageshack.us/a/img69/7765/45q8.png

我尝试在一个更简单的程序中重现这种行为,但即使用ST复制精确的设置,包含Vector的读者,相同的monad/program结构等,简单的测试程序也没有显示出来.简化我的大程序,当删除显然完全不相关的代码时,行为也最终会停止.

QS:

  • 我真的把这个载体保持在20倍左右吗?
  • 如果是的话,我如何实际告诉我+RTS -Hymaximum residency声称我不是,我该怎么做才能阻止这种行为?
  • 如果不是,为什么Haskell没有GC并且没有地址空间/内存,我该怎么做才能阻止这种行为呢?

谢谢!

NBF*_*RTW 2

我怀疑这是 GHC 和/或 RTS 中的错误。

首先,我确信不存在实际的空间泄漏或类似情况。

理由:

  • 该向量从未在任何地方使用过。没有读过,没有写过,没有引用过。runST 完成后应将其收集。即使 ST 计算返回一个 Int 并立即打印出来进行评估,内存问题仍然存在。没有提及该数据。
  • RTS 提供的每种分析模式都强烈同意我实际上从来没有分配/引用超过单个向量的内存。每个统计数据和漂亮的图表都说明了这一点。

现在,这是有趣的一点。System.Mem.performGC如果我在每次运行函数后调用来手动强制 GC ,问题就会完全消失。

因此,我们遇到的情况是,运行时拥有 GB 的内存(显然!)可以由 GC 回收,甚至根据其自己的统计数据,这些内存不再由任何人持有。当内存池用完时,运行时不会收集,而是向操作系统请求更多内存。即使最终失败,运行时仍然不会收集(这显然会回收 GB 的内存),而是选择以内存不足错误终止程序。

我不是 Haskell、GHC 或 GC 方面的专家。但这对我来说确实看起来很糟糕。我会将其报告为错误。