Skip to content

Instantly share code, notes, and snippets.

@rgarcia
Last active August 29, 2015 13:57
Show Gist options
  • Save rgarcia/9377569 to your computer and use it in GitHub Desktop.
Save rgarcia/9377569 to your computer and use it in GitHub Desktop.
node heap wtf
$ node --expose-gc server.js

in another terminal:

$ curl localhost:5001

output in first terminal shows that req.foo is still sitting in the heap:

{ before: 
   { nodes: 27143,
     time: Wed Mar 05 2014 13:59:20 GMT-0800 (PST),
     size_bytes: 4595904,
     size: '4.38 mb' },
  after: 
   { nodes: 25238,
     time: Wed Mar 05 2014 13:59:25 GMT-0800 (PST),
     size_bytes: 84183520,
     size: '80.28 mb' },
  change: 
   { size_bytes: 79587616,
     size: '75.9 mb',
     freed_nodes: 3430,
     allocated_nodes: 1525,
     details: 
      [ [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object] ] } }

var express = require('express');
var memwatch = require('memwatch');
var _ = require('underscore');
var app = express()
var checkHeap = function() {
global.gc();
var diff = snapshot.end();
console.log(diff);
};
var snapshot = null;
app.use(function(req, res, next) {
snapshot = new memwatch.HeapDiff();
req.foo = _.range(10000000); // allocate a ton of space
next();
})
app.use(app.router);
app.get("/", function(req, res, next) {
res.write("hello world");
res.end();
setTimeout(checkHeap, 5000);
})
var server = app.listen(5001);
@defunctzombie
Copy link

I have narrowed it down to this line
https://github.com/visionmedia/express/blob/master/lib/middleware/init.js#L16

If you comment that out, memory is ok (this is an issue on express 3 and 4) and a very good find.

/cc @jonathanong @visionmedia

@tj
Copy link

tj commented Mar 6, 2014

try moving the setTimeout lower (as a setInterval or something)

@defunctzombie
Copy link

I simplified the server code a bit:
https://gist.github.com/defunctzombie/9380299

To help rule out more codepaths

@defunctzombie
Copy link

Making multiple requests (after waiting for the snapshot from each one) does not yield linear memory growth.

@defunctzombie
Copy link

Ok, so adding more gc() calls before the final memory check makes the issue go away. I suspect this is because gc() is more of a hint than an absolute. Someone with more v8 experience needs to comment on that.

@jonathanong
Copy link

hmmm i actually don't think is a problem. i read somewhere that v8 doesn't actually gc() until it starts running out of memory, so unless node is beginning to use a lot of memory, you won't see automatic garbage collection. thus, manually gc()ing multiple times solves the issue.

a real test should be whether the process dies when you continuously hit it with requests.

@jonathanong
Copy link

we could always kill the .next reference when the response emits a finish or close event just to be safe.

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