v8/Node 在函数调用期间是否真的进行了垃圾收集? - 或者这是一个 sailsJS 内存泄漏

Does v8/Node actually garbage collect during function calls? - Or is this a sailsJS memory leak

我正在创建一个带有后台任务的 sailsJS 网络服务器,需要连续 运行(如果服务器空闲)。 - 这是一项将数据库与一些外部数据和 pre-cache 数据同步以加快请求速度的任务。

我使用的是 sails 1.0 版。适配器是postgresql (adapter: 'sails-postgresql'),适配器版本:1.0.0-12

现在,在 运行 运行此应用程序时,我注意到一个主要问题:一段时间后,应用程序似乎莫名其妙地崩溃并出现堆内存不足错误。 (我什至无法捕捉到这一点,节点进程刚刚退出)。

当我试图寻找内存泄漏时,我尝试了很多不同的方法,最终我可以将我的代码缩减为以下函数:

async DoRun(runCount=0, maxCount=undefined) {
  while (maxCount === undefined || runCount < maxCount) {
    this.count += 1;
    runCount += 1;
    console.log(`total run count: ${this.count}`);
    let taskList;
    try {
      this.active = true;
      taskList = await Task.find({}).populate('relatedTasks').populate('notBefore');
      //taskList = await this.makeload();
    } catch (err) {
      console.error(err);
      this.active = false;
      return;
    }
  }
}

为了做到这一点 "testable" 我减小了应用程序允许使用的堆大小:--max-old-space-size=100;使用这个堆大小,它总是在 2000 运行 秒左右崩溃。然而,即使使用 "unlimited" 堆,它也会在几(万)千 运行 秒后崩溃。

现在为了进一步测试,我注释掉了 Task.find() 命令并添加了一个创建 "same" 结果的虚拟对象。

async makeload() {
  const promise = new Promise(resolve => {
    setTimeout(resolve, 10, this);
  });
  await promise;
  const ret = [];
  for (let i = 0; i < 10000; i++) {
    ret.push({
      relatedTasks: [],
      notBefore: [],
      id: 1,
      orderId: 1,
      queueStatus: 'new',
      jobType: 'test',
      result: 'success',
      argData: 'test',
      detail: 'blah',
      lastActive: new Date(),
      updatedAt: Date.now(),
      priority: 2 });
  }
  return ret;
}

这 运行s(到目前为止)即使在 20000 次调用之后也很好,分配了 90 MB 的堆。 在第一种情况下我做错了什么?这让我相信帆有内存泄漏?或者节点无法以某种方式释放数据库连接?

我这里好像看不出有什么明目张胆的"leaking"?正如我在日志中看到的那样,this.count 不是字符串,因此它甚至没有泄漏(运行Count 也是如此)。

从这一点我该如何进步?


编辑 还有一些 clarifications/summary:

我运行 带有标志:--max-old-space-size=100
环境变量:node_env=production

它在生产环境中大约 2000-2500 运行 秒后崩溃(在调试模式下为 500)。


我创建了一个 github 存储库,其中包含一个可行的代码示例; here。再次查看代码 "soon" 设置标志 --max-old-space-size=80 (或类似的东西)

我对sailsJS一窍不通,但是我可以回答标题前半部分的问题:

Does V8/Node actually garbage collect during function calls?

是的,绝对是。细节很复杂(大多数垃圾 collection 工作是在小的增量块中完成的,并且尽可能多地在后台完成)并且随着垃圾收集器的改进而不断变化。基本原则之一是分配触发 GC 工作块。

垃圾收集器不关心函数调用或事件循环。