Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory leak when using streams in Node.js?

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?

like image 202
Golo Roden Avatar asked Oct 23 '13 19:10

Golo Roden


People also ask

How do you prevent memory leaks in node JS?

Avoid Accidental Globals This could be the result of a typo and could lead to a memory leak. Another way could be when assigning a variable to this within a function in the global scope. To avoid issues like this, always write JavaScript in strict mode using the 'use strict'; annotation at the top of your JS file.

How do I fix a process out of memory exception in node JS?

This exception can be solved by increasing the default memory allocated to our program to the required memory by using the following command. Parameters: SPACE_REQD: Pass the increased memory space (in Megabytes).


1 Answers

(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.

like image 142
Laurent Perrin Avatar answered Oct 16 '22 18:10

Laurent Perrin