在 Node.js 中使用流时内存泄漏?

Posted

技术标签:

【中文标题】在 Node.js 中使用流时内存泄漏?【英文标题】:Memory leak when using streams in Node.js? 【发布时间】:2013-11-02 05:32:06 【问题描述】:

假设我有一个简单的 http 服务器,例如:

var http = require('http');

http.createServer(function (req, res) 
  req.on('data', function (data) 
    console.log('Got some data: ' + data);
  );

  req.on('end', function () 
    console.log('Request ended!');
  );

  res.end('Hello world!');
).listen(3000);

所以,基本上是默认的 101 样本,到目前为止没有什么特别的——除了我订阅了可读的req 流的dataend 事件。现在我想知道当我不再需要这些事件时是否必须取消订阅它们?

或者当可读流结束时它们会自动清除?

这样的代码会导致内存泄漏吗?

【问题讨论】:

This 可能会有所帮助。 这在更普遍的意义上实际上是有帮助的。谢谢:-) 【参考方案1】:

(此答案包含指向 node.js 源代码相关部分的链接)

在回答您的问题之前,让我们先谈谈事件。当你这样做时:

emitter.on('an-event', listener);

listener 被添加到附加到 emitter 的 list 中。稍后,当emitter 触发事件时,它会通过遍历列表的方式通知所有订阅该事件的监听器。 node.js 事件发射器的神奇之处在于您无需自己声明或管理该列表。

但是,无论何时调用 .on(),都会创建一个 back-reference 发射器 -> 侦听器。如果您从未取消订阅,此引用将阻止 GC 收集侦听器并创建“泄漏”。

这在 node.js 中不会经常发生,因为通常,发射器在侦听器之前被销毁,但发生这种情况的实际情况是当您有一个长时间运行的连接(想想 Twitter 流 API)时,有时会重新连接。如果您不取消注册事件,您可能会从旧连接中获取事件并认为它们适用于新连接。这可能会让您认为新连接已关闭。

当 node.js 认为您可能忘记注销监听器时,它会打印臭名昭著的 "possible leak detected" 消息。

回到你的例子:

这不会造成泄漏,因为套接字 (req+res) 将首先被销毁。由于是发射器,node.js 将forcibly remove all listeners.

【讨论】:

很好的答案,非常感谢,尤其是发射器被破坏的部分。 :-)

以上是关于在 Node.js 中使用流时内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章

检测代码中的 node.js/javascript 内存泄漏

node.js内存泄漏分析二

Node.js内存泄漏分析

Node.js中的内存泄漏分析

使用 Node.js 服务器调试内存泄漏

Node.js 内存泄漏?