Last active
May 28, 2016 17:59
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
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.
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
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
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
Sometimes
fs.createReadStream
never finishesOr maybe it doesn't always propagate to the next stream?
Run the server
node server.js
, and hit it hard with theloadtest
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:
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 theContent-Length
header modify the request behavior?Help?