【问题标题】:Memory leak in a haskell programhaskell 程序中的内存泄漏
【发布时间】:2014-01-18 21:16:03
【问题描述】:

我一直在尝试使用 haskell 程序阅读和索引一组链接和维基百科摘要。目的是

  1. 从文件中读取一行
  2. 解析它
  3. 对行的某些部分以及文件中的偏移量进行哈希和索引,以便我以后找到它

问题是我的程序非常慢并且使用大量内存。我做了一些分析,我知道大部分时间(~50%)都花在了垃圾收集上。我已经尝试了我能想到的一切来达到我现在所拥有的,包括:

  1. 以 Data.Map 作为存储的 ST monad 东西
  2. 使用散列值作为键,而不是保留整个字节串
  3. 使用 seq 和 deepseq 尝试防止延迟分配
  4. 逐行解析,而不是希望懒惰可以使解析行列表节省空间和时间
  5. 使用不可变哈希图而不是 Data.Map
  6. 使用可变哈希图

代码、数据、分析输出和编译的东西:https://gist.github.com/ririw/8205284

谢谢!

【问题讨论】:

  • 这些行对我来说看起来很可疑:let parsed = parseOnly linkLineParser line in parsed 'par' case (parseOnly linkLineParser line) of,您应该将其更改为更像 popAbstract 的情况已结束parsed。我认为您正在对 NTEntries 进行全面评估。 (所以 cmets 不让我很好地格式化它)
  • 啊,很好,我想我改变了抽象的,忘了做链接。但这仍然不能解决问题。我认为我错过了一些关于内存分配如何工作或我应该如何处理数据的根本重要部分,这可能会阻止 GC 不得不移动这么多。
  • 虽然我无法在性能方面为您提供帮助,但我可以推荐 hackage.haskell.org/package/swish-0.9.0.11/docs/… 以便于解析
  • 令我惊讶的是resourceName 完成了 27% 的分配。有趣的是,当我运行程序时,link 也完成了 23% 的分配。分析器的输出是否与 gist 中编写的程序完全一致?否则我不明白区别。无论如何,似乎takeWhileskipWhile 做了很多分配。也许attoparsecbytestring 专家可以提供帮助。
  • 我想我一定是不小心启动了旧的分析器运行。我通过从使用 (.*>) :: ByteString -> Parser a -> Parser a 切换到使用 string :: ByteString -> Parser ByteString 解决了这个问题。

标签: haskell memory-management garbage-collection


【解决方案1】:

好的,我已经设法将我的测试集的内存使用减少了 100MB 左右(dbpedia 链接数据集的前 400K 行,可在 http://downloads.dbpedia.org/3.9/en/wikipedia_links_en.nt.bz2 获得)。

我通过切换到 io-streams 库来做到这一点,这似乎解决了一些懒惰的问题。

您可以在https://gist.github.com/ririw/8207250看到新的解决方案

在一个 7574825 行的数据集上它运行良好,并且内存使用量以我期望哈希表在它自己填充和随机排列的方式上增加(http://imgur.com/pcDnKcP)。当然,也可能是 io-streams 缓冲区做同样的事情。

它仍然使用大量内存 :(,但我认为已经解决了惰性/io 问题

【讨论】:

  • 仍有 17% 的分配在 resourceName 中完成,这仍然让我感到惊讶。我不明白为什么它必须分配。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 2021-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多