I have an application where I am sequentially downloading mp3 files from a server, storing them in my server temporarily, then streaming them directly to clients, like so:
function downloadNextTrack(){
var request = http.get('http://mp3server.com', function(response){
response.on('data', function(data) {
fs.appendFile('sometrack.mp3', data, function (err) {});
});
response.on('end', function(){
streamTrack('sometrack.mp3');
}
});
};
var clients = []; // client response objects are pushed to this array when they request the stream through a route like /stream.mp3
var stream;
function streamTrack(track){
stream = fs.createReadStream(track);
stream.on('data', function(data){
clients.forEach(function(client) {
client.write(data);
});
});
stream.on('end', function(){
downloadNextTrack(); // redoes the same thing with another track
}
};
Apparently this code is creating a lot of buffers which aren't being freed by the OS, when I run 'free -M' command, this is what I get (after about 4 hours of running the app):
total used free shared buffers cached
Mem: 750 675 75 0 12 180
-/+ buffers/cache: 481 269
Swap: 255 112 143
The number under 'buffers' constantly rises (as well as the cached memory) and the OS apparently doesn't reclaim that 180mb back, until eventually my app runs out of memory and crashes when I try spawning a small process to verify a track's bitrate, sampling rate, id3 info, etc.
I have diagnosed with a lot of different tools (such as memwatch and nodetime) to find out if it was an internal memory leak and it isn't, the V8 memory heap as well as the Node RSS vary +/- 10mb but stay constant for most part while the OS free memory gets lower and lower (when the Node process starts I have about 350MB of free memory).
I read somewhere that Buffer instances allocated by Node have direct access to raw memory and so V8 doesn't have power over them (which checks out with the fact that I am not getting memory leaks from the V8 heap), the thing is, I need a way to get rid of these old buffers. Is this possible? Or will I have to restart my app every 5 hours or so (or worse, buy more RAM!)?
PS. I am running Node v0.8.16 on Ubuntu 10.04.
The slice() method returns a new buffer object, using parts of an existing buffer. The start and end parameters specifies where to start and end the extraction.
The Buffer. alloc() method creates a new buffer object of the specified size.
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.
Buffers have a toString() method that you can use to convert the buffer to a string. By default, toString() converts the buffer to a string using UTF8 encoding. For example, if you create a buffer from a string using Buffer. from() , the toString() function gives you the original string back.
I agree with Tiago, I think this is caused because of the recursive nature of your code. I don't think the streams is what gobbling up your heap, because as you said, the stream variable is being reassigned with a new ReadStream with every iteration. However, the http.get's request and response (and whatever Buffers they use) in line 2 are never being released before calling the next iteration; they are scoped within the downloadNextTrack function. You end up with a recursive stack trace that has a set of request and response objects (and some underlying buffers) per file.
In general, if this code needs to run many, many times, why not opt-out of the recursion and do it all iteratively? a never-ending recursion will always gobble more and more memory, until the program crashes, even if there's no memory leaks on your part.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With