8

假设我有一个简单的 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 样本,到目前为止没有什么特别的——除了我订阅了可读流的data和事件。现在我想知道当我不再需要这些事件时是否必须取消订阅它们?endreq

还是在可读流结束时自动清除它们?

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

4

1 回答 1

17

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

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

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

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

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

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

当node.js认为您可能忘记取消注册侦听器时,它会打印臭名昭著的“检测到可能泄漏”消息。

回到你的例子:

这不会造成泄漏,因为套接字 (req+res) 将首先被销毁。由于是发射器,node.js 会强制移除所有的 listeners

于 2013-10-31T14:17:22.850 回答