Memory leak when using streams in Node.js?

2019-02-22 04:45发布

Supposed I have a simple http server such as:

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);

So, basically the default 101 sample, nothing special so far - except that I subscribe to the data and the end event of the readable req stream. Now I wonder whether I have to unsubscribe those events when I no longer need them?

Or are they cleared automatically when the readable stream ends?

Could code like this cause a memory leak?

1条回答
女痞
2楼-- · 2019-02-22 05:44

(This answer contains links to the revelant parts of the node.js source code)

Before answering your question, let's talk about events. When you do this:

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

listener gets added to a list attached to emitter. Later, when emitter triggers the event, it notifies all the listeners subscribed to the event by iterating through the list. The magic of node.js event emitters is that you don't declare or manage that list yourself.

However, whenever you call .on(), you create a back-reference emitter -> listener. This reference will prevent the listener from being collected by the GC and create a "leak" if you never unsubscribe.

This does not happen very often with node.js, because usually, emitters are destroyed before listeners, but a real-world case where this happens is when you have a long running connection (think Twitter Streaming API) that sometimes reconnects. If you don't unregister events, you might get events from the old connection and think they apply to the new one. This can lead you to think the new connection has closed.

node.js will print the infamous "possible leak detected" message when it thinks you might be forgetting to unregister listeners.

Back to your example:

This won't create a leak because the socket (req+res) will be destroyed first. Since it's the emitter, node.js will forcibly remove all listeners.

查看更多
登录 后发表回答