更新 mongodb 时 JavaScript 堆内存不足

Posted

技术标签:

【中文标题】更新 mongodb 时 JavaScript 堆内存不足【英文标题】:JavaScript heap out of memory while updating the mongodb 【发布时间】:2019-09-21 15:20:52 【问题描述】:

我正在尝试在数据存储之间同步数据,源是 mssql,目标是 MongoDB。在此同步过程中,我遇到了内存堆错误。我不确定为什么会发生这种情况,并且我完全意识到以下代码可能不是最好的,但现在我只是想了解为什么会出现分配错误。

我正在用 babel 编译我的代码,在开发中我只是使用 babel-node。

try 
  const response = await sqlDataStore.findAll(
    attributes: ['id', 'Name'],
  );
  /* eslint no-restricted-syntax: 0 */
  for (const item of response) 
    /* eslint no-await-in-loop: 0 */
    await this.Model.updateOne(, item,  upsert: true );
  
 catch (err) 
  console.log(err);

如果我理解正确,堆错误是由 for 循环引起的,那么这意味着每个 await 语句都缓存在内存中。我本来希望每个 await 语句都从内存中清除,因为我没有将它分配给任何变量。

更新:

很高兴我已经找到了解决方案,因为另一个帖子:Bulk upsert in MongoDB using mongoose

我的代码:

  const response = await sqlDataStore.findAll(
    attributes: ['id', 'Name'],
  );

  const bulkUpdate = response.map(doc => (
    updateOne: 
      filter:  _id: doc.id ,
      update: doc.dataValues,
      upsert: true,
    ,
  ));

  this.Model.collection.bulkWrite(bulkUpdate);

如果有人使用此解决方案,请记住,这也可能导致大量数据崩溃。其他帖子中提供的解决方案建议在更新/插入每个文档之前,应在 1000 个桶中处理数据。

仅出于兴趣和技术理解,我希望能解释一下我在第一个代码中到底做错了什么。

【问题讨论】:

只是为了确定,代码在第一个 SQL 查询中运行良好吗?也就是说,是不是引入的数据量太大了? 是的,sql查询绝对没问题,数据量也不大,只有2401行。 查看这个eslint.org/docs/rules/no-await-in-loop 嗨,我知道操作被延迟了,但这不是我的问题,问题是它们是否确实存储在内存中,以及即使我没有将响应存储在任何内容中,这是否是预期的行为变量。 我猜这是因为您的执行完全阻塞了下一次执行,并且将在内存中直到您的整个执行完成。检查我分享的链接。 【参考方案1】:

你得到这个是因为你的函数调用堆栈没有得到空闲,因为它们正在等待其他调用完成它的执行。

由于所有调用堆栈都阻塞了您的堆栈内存,因此在执行一些操作后您将遇到内存不足异常。

检查此链接: https://eslint.org/docs/rules/no-await-in-loop

如您所见,您的 await 调用在内存中被阻塞,等待其他 await 完成,他们一次性返回您的值,这对您的代码不利。

实际上是您正在进行同步调用,并且每个同步调用都在等待其他同步调用完成,最后,您的同步调用堆积在堆栈内存中并且您遇到了异常 .

【讨论】:

以上是关于更新 mongodb 时 JavaScript 堆内存不足的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB - 使用 javascript 更新子文档

javascript 如何在mongodb中更新集合?

javascript 具有另一个字段值的mongodb更新字段

javascript 如何在mongodb中更新集合中的所有文档?

MongoDB 更新插入 $in

在 mongodb 和节点 js 中堆内存不足