NodeJS内存不足,使用具有异步功能的for循环

时间:2016-08-27 09:15:11

标签: node.js asynchronous

exports.updateFullCentralRecordSheet = function (req, _id, type) {
  FullCentralRecordSheet.remove({_ExternalParty: _id, centralRecordType: type, centralSheetType: "Central Sheet"}, function (err) {
    if (err) {
      saveErrorLog(req, err);
    }
    let query = {"structure.externalPartyRelationships": {$elemMatch: {_ExternalParty: _id}}, disabled: {$mod: [2, 0]}, initialized: true, profitLossType: type};
    let fullCentralRecordSheetObjects = [];
    ProfitLossSheet.find(query).sort({profitLossDate: 1}).lean().exec(function (err, profitLossSheetObjects) {
      if (err) {
        saveErrorLog(req, err);
      }
      async.each(profitLossSheetObjects, function (profitLossSheetObject, callback) {
          /// HEAVY COMPUTATION HERE
          callback();
        });
      }, function (err) {
        if (err) {
          saveErrorLog(req, err);
        } else {
          query = {centralRecordMode: {$in: ["Payment In", "Payment Out", "Transfer", "General Out"]}, disabled: {$mod: [2, 0]}, centralRecordType: {$in: ["Split", type]}, _ExternalParty: _id, status: {$ne: "Reject"}};
          CentralRecordSheet.find(query).lean().exec(function (err, centralRecordSheetObjects) {
            if (err) {
              saveErrorLog(req, err);
            }
            _.each(centralRecordSheetObjects, function (centralRecordSheetObject) {
               // SOME MORE PROCESSING
            });
            fullCentralRecordSheetObjects = _.sortBy(fullCentralRecordSheetObjects, function (fullCentralRecordSheetObject) {
              return new Date(fullCentralRecordSheetObject.centralRecordDate).getTime();
            });
            let runningBalance = 0;
            _.each(fullCentralRecordSheetObjects, function (fullCentralRecordSheetObject) {
              runningBalance = runningBalance - fullCentralRecordSheetObject.paymentIn.total + fullCentralRecordSheetObject.paymentOut.total + fullCentralRecordSheetObject.moneyIn.total - fullCentralRecordSheetObject.moneyOut.total + fullCentralRecordSheetObject.transferIn.total - fullCentralRecordSheetObject.transferOut.total;
              fullCentralRecordSheetObject.balance = runningBalance;
              const newFullCentralSheetRecordObject = new FullCentralRecordSheet(fullCentralRecordSheetObject);
              newFullCentralSheetRecordObject.save(); // Asynchronous save
            });
          });
        }
      });
    });
  });
};

这是我处理一些数据并将其保存到数据库的代码。正如您所看到的,每个异步循环都涉及一些计算,循环之后会有最终的数据处理。如果我一次传入一个_id,它工作正常。但是,当我尝试像这样执行任务时

exports.refreshFullCentralRecordSheetObjects = function (req, next) {
      ExternalParty.find().exec(function (err, externalPartyObjects) {
        if (err) {
          utils.saveErrorLog(req, err);
          return next(err, null, [req.__(err.message)], []);
        }
        _.each(externalPartyObjects, function (externalPartyObject) {
            updateFullCentralRecordSheet(req, externalPartyObject._id, "Malay");
            updateFullCentralRecordSheet(req, externalPartyObject._id, "Thai");
        })
        return next(err, null, ["Ddd"], ["Ddd"]);
      });
    };

我有大约273个对象要循环。这会导致内存致命错误。我试图增加--max-old-space-size=16000,但它仍在崩溃。我使用任务管理器来跟踪node.exe进程的内存,它超过8 GB。

我不确定为什么增加16GB的内存没有帮助,它仍然会在8GB左右崩溃(根据任务经理的说法)。另一件事是当我尝试仅处理10个记录而不是273时,任务管理器报告它使用大约500 MB。除非我向服务器发出另一个请求,否则此500 MB不会消失。我发现这很奇怪,因为在完成处理10条记录后,为什么NodeJS不会收集垃圾?这10条记录已成功处理并保存到数据库,但任务管理器中的内存使用情况保持不变。

我尝试使用async.forEachLimit,将我的更新功能变为异步,使用process.nextTick(),但我仍然有致命的错误内存问题。我该怎么做以确保这个运行?

1 个答案:

答案 0 :(得分:0)

  

另一件事是我尝试只处理10条记录而不是273条记录,   任务管理器报告它使用大约500 MB。这个500 MB会   除非我向服务器发出另一个请求,否则不会消失。我找到了这个   非常奇怪,因为NodeJS完成后为什么不收集垃圾   处理10条记录?这10条记录已成功处理   并保存到数据库但是内存使用量保持不变   任务经理。

这是正常的,节点GC是懒惰的(GC是同步操作,阻塞循环,所以这是一件好事)。

尝试对查询进行分页?