Skip to content

Instantly share code, notes, and snippets.

@evantahler
Last active May 28, 2016 17:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save evantahler/2f6c4241c47d7c89f5555d833475c8b8 to your computer and use it in GitHub Desktop.
Save evantahler/2f6c4241c47d7c89f5555d833475c8b8 to your computer and use it in GitHub Desktop.
Exploring a node.js memory leak with sending files and setting the Content-Length header
var fs = require('fs');
var http = require('http');
var file = __dirname + '/index.html';
var connections = {};
var idCouner = 0
var port = 8080;
var handleRequset = function(request, response){
idCouner++
var id = idCouner;
connections[id] = {req: request, res: response};
response.on('finish', function(){
delete connections[id];
});
fs.stat(file, function(error, stats){
if(error){ throw error; }
response.writeHead(200, [['Content-Length', stats.size]]);
var fileStream = fs.createReadStream(file);
fileStream.on('open', function(){
fileStream.pipe(response);
});
fileStream.on('error', function(error){
console.log(error); // no errors are caught
});
});
};
http.createServer(handleRequset).listen(port);
console.log('server running on port ' + port);
setInterval(function(){
console.log('connections: ' + Object.keys(connections));
}, 5000);
@evantahler
Copy link
Author

evantahler commented May 20, 2016

Sometimes fs.createReadStream never finishes

Or maybe it doesn't always propagate to the next stream?

Run the server node server.js, and hit it hard with the loadtest package.

  • npm install loadtest
  • ./node_modules/.bin/loadtest -c 10 --rps 200 http://localhost:8080

If let run long enough, the count of un-finished connections will grow linearly with time:

> node server
server running on port 8080
connections: 0
connections: 0
connections: 2
connections: 2
connections: 2
connections: 4
connections: 4
connections: 4
connections: 5
connections: 6
connections: 6
connections: 6
connections: 6
connections: 6
connections: 7
connections: 9
connections: 9
connections: 9
connections: 9
connections: 11
connections: 9
connections: 11
connections: 12
...

This seems to indicate that there is a small problem < ~1% of the time, where the finished event isn't emitted. If you remove line 15, everything is fine, and the number of un-finished connections stays low and constant. How does sending the Content-Length header modify the request behavior?

Help?

@crrobinson14
Copy link

I confirmed this on Node 4.2.3 and 6.2.0 (using NVM). I can also confirm that removing the "Content-Length" writeHead line eliminates the problem.

@evantahler
Copy link
Author

I've modified the code a bit to give each connection and ID, and return those IDs every 5 seconds so we can prove that the same connections are in fact 'stuck' in an un-finished state.

> node server.js
server running on port 8080
connections:
connections: 2867
connections: 2867
connections: 2867
connections: 2867
connections: 2867
connections: 2867
connections: 2867
connections: 2867
connections: 2867
connections: 2867,12403
connections: 2867,12403
connections: 2867,12403
connections: 2867,12403
connections: 2867,12403
connections: 2867,12403
connections: 2867,12403
connections: 2867,12403
connections: 2867,12403
connections: 2867,12403
connections: 2867,12403,22350
connections: 2867,12403,22350

@n-s-k
Copy link

n-s-k commented May 21, 2016

Confirmed on Node 4.2.4 (Windows 7):

λ node server.js
server running on port 8081
connections: 19,20,21,63,103,105,114,124,197,847,853,1046,1105
connections: 19,20,21,63,103,105,114,124,197,847,853,1046,1105,1210,1266,1290,1297,1583,1714,2047,2203
connections: 19,20,21,63,103,105,114,124,197,847,853,1046,1105,1210,1266,1290,1297,1583,1714,2047,2210,2234,2413,2542,2657,2706,2708,2709,3205
connections: 19,20,21,63,103,105,114,124,197,847,853,1046,1105,1210,1266,1290,1297,1583,1714,2047,2210,2234,2413,2542,2657,2706,2708,2709,3275,3346,3523,3525
connections: 19,20,21,63,103,105,114,124,197,847,853,1046,1105,1210,1266,1290,1297,1583,1714,2047,2210,2234,2413,2542,2657,2706,2708,2709,3275,3346,3523,3525,4269
connections: 19,20,21,63,103,105,114,124,197,847,853,1046,1105,1210,1266,1290,1297,1583,1714,2047,2210,2234,2413,2542,2657,2706,2708,2709,3275,3346,3523,3525,4269,5416,5783,5784,5865,6147,6148
connections: 19,20,21,63,103,105,114,124,197,847,853,1046,1105,1210,1266,1290,1297,1583,1714,2047,2210,2234,2413,2542,2657,2706,2708,2709,3275,3346,3523,3525,4269,5416,5783,5784,5865,6147,6148,6563,6779,7139,7140
connections: 19,20,21,63,103,105,114,124,197,847,853,1046,1105,1210,1266,1290,1297,1583,1714,2047,2210,2234,2413,2542,2657,2706,2708,2709,3275,3346,3523,3525,4269,5416,5783,5784,5865,6147,6148,6563,6779,7139,7140,7318,8214

@evantahler
Copy link
Author

Please move conversation about this issue to nodejs/node#6929

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment