haskell - 我应该如何解释 ghc 堆分析器的输出?

标签 haskell

我有一个在 haskell 中实现的服务器进程,它充当一个简单的内存数据库。客户端进程可以连接然后添加和检索数据。该服务使用的内存比我预期的要多,我正在尝试找出原因。

我拥有的最粗略的衡量标准是 linux “top”。当我开始这个过程时,我看到一个“VIRT”图像大小约为 27MB。运行客户端插入 60,000 个数据项后,我看到图像大小约为 124MB。

运行捕获 GC 统计信息的过程(+RTS -S),我最初看到

Alloc    Copied     Live    GC    GC     TOT     TOT  Page Flts
bytes     bytes     bytes  user  elap    user    elap
28296      8388      9172  0.00  0.00    0.00    0.32    0    0  (Gen:  1)

在添加 60k 项时,我看到实时字节平稳增长到
   ...
   532940     14964  63672180  0.00  0.00   23.50   31.95    0    0  (Gen:  0)
   532316      7704  63668672  0.00  0.00   23.50   31.95    0    0  (Gen:  0)
   530512      9648  63677028  0.00  0.00   23.50   31.95    0    0  (Gen:  0)
   531936     10796  63686488  0.00  0.00   23.51   31.96    0    0  (Gen:  0)
   423260  10047016  63680532  0.03  0.03   23.53   31.99    0    0  (Gen:  1)
   531864      6996  63693396  0.00  0.00   23.55   32.01    0    0  (Gen:  0)
   531852      9160  63703536  0.00  0.00   23.55   32.01    0    0  (Gen:  0)
   531888      9572  63711876  0.00  0.00   23.55   32.01    0    0  (Gen:  0)
   531928      9716  63720128  0.00  0.00   23.55   32.01    0    0  (Gen:  0)
   531856      9640  63728052  0.00  0.00   23.55   32.02    0    0  (Gen:  0)
   529632      9280  63735824  0.00  0.00   23.56   32.02    0    0  (Gen:  0)
   527948      8304  63742524  0.00  0.00   23.56   32.02    0    0  (Gen:  0)
   528248      7152  63749180  0.00  0.00   23.56   32.02    0    0  (Gen:  0)
   528240      6384  63756176  0.00  0.00   23.56   32.02    0    0  (Gen:  0)
   341100  10050336  63731152  0.03  0.03   23.58   32.35    0    0  (Gen:  1)
     5080  10049728  63705868  0.03  0.03   23.61   32.70    0    0  (Gen:  1)

这似乎告诉我堆有大约 63MB 的实时数据。当您添加堆栈空间、代码空间、GC 开销等时,这很可能与顶部的数字一致。

所以我尝试使用堆分析器来确定是什么组成的
这 63MB。结果令人困惑。运行“+RTS -h”,查看
生成的 hp 文件,最后一个也是最大的快照有:
containers-0.3.0.0:Data.Map.Bin 1820400
bytestring-0.9.1.7:Data.ByteString.Internal.PS  1336160
main:KV.Store.Memory.KeyTree    831972
main:KV.Types.KF_1  750328
base:GHC.ForeignPtr.PlainPtr    534464
base:Data.Maybe.Just    494832
THUNK   587140

快照中的所有其他数字都比这小得多。
将这些相加得出的峰值内存使用量约为 6MB,如
图表输出:

enter image description here

为什么这与 GC 统计信息中显示的事件字节不一致?它是
很难看出我的数据结构可能需要 63MB,而且
探查器说他们不是。内存去哪儿了?

感谢您对此的任何提示或指示。

蒂姆

最佳答案

我有一个理论。我的理论是你的程序使用了很多类似 ByteStrings 的东西。 .我的理论是因为ByteStrings的主要内容是 malloc ated,它们在分析时不会显示。因此,如果堆的最大内容没有显示在分析图上,您可能会用完堆。

更糟糕的是,当您获取 ByteStrings 的子字符串时,它们默认保留指向最初分配的内存块的指针。因此,即使您尝试只存储一些 ByteString 的小片段您最终可能会保留整个最初分配的 ByteString这不会显示在您的堆配置文件中。

无论如何,这是我的理论。我对 GHC 的堆分析器如何工作以及 ByteStrings 的工作原理知之甚少。实现是为了确定。也许其他人可以插话并证实或质疑我的理论。

Edit2: tibbe 指出 ByteString 使用的缓冲区s 被固定。因此,如果您要分配/释放大量小 Bytestring s,你可以分割你的堆,这意味着你用完了可用的堆,其中一半未分配。

编辑:JaffaCake 告诉我,有时堆分析器不会显示 ByteStrings 分配的内存。

关于haskell - 我应该如何解释 ghc 堆分析器的输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5306717/

相关文章:

list - 计算有序列表中的元素

haskell - 如何为 `llvm` 和 `ghc` 指定到 `cabal` 的路径?

haskell - 柯里化(Currying)带有 n(3 个或更多)参数的函数?

function - Haskell 和一般类型

haskell - 如何在每次连续执行后打印出内存状态?

haskell - 树莓派 2 上的 GHCi?

Haskell 新手 : No instance for Show in map function

haskell - ':..' 在 Haskell 中意味着什么?

string - 缩进字符串中的所有行

haskell - 为非空列表定义类型