Skip to content

Instantly share code, notes, and snippets.

@isaacs
Created January 2, 2015 00:54
Show Gist options
  • Save isaacs/f5920e5c6985f1e4a9dd to your computer and use it in GitHub Desktop.
Save isaacs/f5920e5c6985f1e4a9dd to your computer and use it in GitHub Desktop.
// A "memory leak" means that, even after garbage collection, memory is still
// not released to the system. Note that this is different from "using a lot
// of memory".
//
// It's of course possible to do things that prevent garbage collection, which
// is a memory leak in JavaScript. (As opposed to a memory leak in the
// JavaScript implementation.)
//
// Even if you do not leak memory, and the implementation does not leak memory,
// if you never hit V8's GC heuristic case, then you might keep *using* a lot
// of memory that is not collected.
//
// In this example, we use the --expose_gc flag which creates a global gc()
// function, so that we can explicitly trigger full garbage collection. Only
// bother to do so right before getting the memory usage, so that we can get
// as many iterations as possible between each test, and increase the
// likelihood of finding some leaks.
if (process.argv[2] === 'child') {
child();
} else {
parent();
}
function parent () {
var spawn = require('child_process').spawn;
var c = spawn(process.execPath, ['--expose_gc', __filename, 'child']);
var d = '';
c.stdout.setEncoding('utf8');
c.stdout.on('data', function (data) {
d += data;
});
var runtime = 25000;
console.log('letting child run for %d ms', runtime);
setTimeout(parse, runtime);
function parse() {
c.kill();
var results = [];
d.trim().split('\n').forEach(function (line) {
// console.error(line);
var data = JSON.parse(line);
results.push(data);
});
// Just in case they came in out of order, though that
// should never ever happen, I'm paranoid I guess.
results = results.sort(function (a, b) {
return a.when - b.when;
});
// dump all the data.
// console.error(results);
console.log('RSS');
console.log(results.map(function (data) {
return data.rss;
}).join('\n'));
console.log('----\nHEAP USED');
console.log(results.map(function (data) {
return data.heapUsed;
}).join('\n'));
console.log('----\nHEAP TOTAL');
console.log(results.map(function (data) {
return data.heapTotal;
}).join('\n'));
}
}
function child () {
var testInterval = 1000;
var total = 0;
var timerTime = Date.now();
var timer = setTimeout(function X () {
var now = Date.now();
total++;
if (now - timerTime > testInterval) {
gc();
var data = process.memoryUsage();
data.when = now;
data.which = 'timeout';
data.total = total;
console.log('%j', data);
timerTime = now;
}
timer = setTimeout(X);
});
var intervalTime = Date.now();
setInterval(function X () {
var now = Date.now();
total++;
if (now - intervalTime > testInterval) {
gc();
var data = process.memoryUsage();
data.when = now;
data.which = 'interval';
data.total = total;
console.log('%j', data);
intervalTime = now;
}
});
}
@isaacs
Copy link
Author

isaacs commented Jan 2, 2015

Results on my system:

letting child run for 25000 ms
RSS
15953920
16310272
16326656
16330752
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
16334848
----
HEAP USED
1964624
2221728
2242096
2242992
2210176
2068112
1983768
1999784
2015328
2018096
2018560
2012480
1984224
2000688
2016072
2018656
2018960
2013376
1985080
1999696
2016168
2018784
2019216
2013048
1984120
2000544
2015984
2018360
2018664
2013080
1984920
2000352
2016368
2018744
2019048
2013832
1984968
1999184
2014800
2017176
2017480
2012136
1983848
2000480
2016384
2018872
2019176
2013088
----
HEAP TOTAL
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968
6163968

Doesn't look like a memory leak to me. And this is doing many many thousands of timeouts, and an interval that's firing many many thousands of times.

Another interesting test might be to run a whole lot of intervals and timers in parallel, and make sure that they don't leak when used all at the same time?

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