【问题标题】:fatal error out of memory内存不足的致命错误
【发布时间】:2014-01-25 04:36:16
【问题描述】:

所以我在 go 中编写了一个守护进程来处理大约 80 万个文档,但我遇到了内存不足的问题。

从我在从 mongodb 获取文档时看到的情况来看,内存使用量随着每个循环而增加。

func main() {
session, err := mgo.Dial("localhost")
if err != nil { panic(err) }
defer session.Close()

subscriptionsC  = session.DB("sm").C("subscriptions")
subscriptions   := []Subscription{}

for {
    subscriptions = GetSubscriptions()

另外一个功能是:

func GetSubscriptions()([]Subscription) {
    result  := []Subscription{}
    err    := subscriptionsC.Find(nil).Prefetch(0.0).All(&result)

    if err != nil { Log("signups_err", err.Error() + "\n") }
    return result
}

我不知道它是否在每个循环中重新声明了数组,或者到底发生了什么。

任何帮助将不胜感激。

【问题讨论】:

  • 您的 for 循环是一个无限循环,只是在每次迭代时从 Mongo 收集结果。
  • 会话是否可能正在缓存您的结果?您可以尝试在每次循环运行时关闭/重新创建您的 subscriptionsC 对象作为测试。
  • stackoverflow.com/questions/21815635/… 遵循此以获得快速和快速的解决方案。

标签: go mgo


【解决方案1】:

这里是mgo的作者。

您的代码没有任何问题,但它不完整,因此您未显示的内容很可能实际上是内存泄漏。

你能提供一个泄露内存的完整例子吗?

顺便说一句,缓存/池会话没有意义,因为 mgo 在内部为您处理资源池。您必须做的是确保关闭您创建的会话,示例代码就是这样做的。

在 OP 发表评论后更新:

似乎问题出在大量文档上。 pastebin.com/jUDmbS4z 这将每 10-15 分钟(大约 4-5 个循环)崩溃一次。它在一个循环中从 mongo 获取了大约 600k 文档。

是的,运行一次在内存中加载大量数据的查询很容易因为与 mgo 无关的多种原因造成麻烦。内存碎片、非精确收集器等。只需在项目到达时对其进行迭代照常;正如您已经想到的那样,它舒适、快速,并且会显着减少内存使用量。

【讨论】:

  • 问题是我更改为不从集合中获取所有内容,并且该守护程序现在工作正常,自 1 月 7 日以来没有更多的内存泄漏并且从未重新启动。似乎问题出在大量文档上。 pastebin.com/jUDmbS4z 这将每 10-15 分钟崩溃一次(大约 4-5 个循环)。它在一个循环中从 mongo 获得了大约 600k 文档。我认为 forEach() 而不是填充数组会修复它,但也会增加查询的数量。
  • 哈……好吧。那么您正在使用大量内存。这不是 mgo 的泄漏。更新了响应。
  • 从来没有说过,我想更多的是一个 golang 错误,但他们说他们用最新版本修复了它。
【解决方案2】:

由于调用GetSubscriptions(),然后在循环内部result := []Subscription{},数组肯定会在每个循环中初始化,但我认为这不是问题的根源。

问题可能来自您的全局会话,请参阅Database connections in web applications,正确的方法是使用会话池。

编辑:另见How do I call mongoDB CRUD method from handler?

【讨论】:

  • 我得到的错误是:pastebin.com/n9b0teSR。其中 139 是 GetSubscriptions() 中的“错误”,166 是 subscriptions = GetSubscriptions()
  • 正是err 是由subscriptionsC 引起的,这就是为什么我怀疑您应该使用另一种模式而不是全局会话。见:groups.google.com/d/msg/mgo-users/d62BH1iuzFc/J1cgd5gWjnUJ
  • 谢谢伙计。在这样做之前,我在查询中使用 $where 进行了测试。似乎如果返回的记录数较少,则内存使用情况稳定,垃圾收集也正常工作。
  • 没有理由在 mgo 中使用会话池,因为资源(例如套接字)在池中内部维护。只需根据需要创建和关闭会话。
  • @GustavoNiemeyer 我无法删除我的答案,因为 OP 已经选择了它。如果它改变了,我会删除它。
猜你喜欢
  • 2014-06-01
  • 2011-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-08
  • 2011-10-28
  • 1970-01-01
相关资源
最近更新 更多