关于node.js:更新mongodb时JavaScript堆内存不足

JavaScript heap out of memory while updating the mongodb

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

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

1
2
3
4
5
6
7
8
9
10
11
12
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语句,因为我没有将其分配给任何变量。

已更新:

很高兴我已经找到了一个解决方案,这要归功于另一篇文章:使用mongoose在MongoDB中批量上传

我的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
  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个存储桶中处理数据,直到每个文档都被更新/插入。

仅出于兴趣和技术上的理解,我将对我在第一个代码中确实做错了什么进行解释。


之所以得到这个,是因为您的函数调用堆栈没有释放,因为他们正在等待其他调用以完成其执行。

由于所有调用堆栈都阻塞了您的堆栈内存,因此在执行某些代码后,您将出现内存不足异常。

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

您可以看到您的await呼叫在内存中被阻塞,以等待其他await完成,并且它们正在一次性返回您的值,这在您的代码中是很糟糕的。

实际上是您在进行同步通话,每个同步通话都在等待其他同步通话结束,最后,您的同步通话堆积在堆栈内存中,并且您遇到异常