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

时间:2013-10-23 19:01:06

标签: node.js memory-leaks

假设我有一个简单的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事件。现在我想知道当我不再需要它们时是否必须取消订阅这些事件?

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

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

1 个答案:

答案 0 :(得分:15)

(这个答案包含指向node.js源代码的重要部分的链接)

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

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

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

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

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

node.js会在认为您可能忘记取消注册侦听器时打印臭名昭着的"possible leak detected"消息。

回到你的例子:

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