我有以下程序不断增加其堆。这是一个非常简单的程序,它通过SyntaxError
重复加载外部文件(require
)。由于语法错误,外部模块无法加载。
我运行节点垃圾收集器并转储堆大小以查看内存是否泄漏。如果我修复了外部文件(SyntaxError.js
)中的语法错误,那么泄漏就会消失,并且在一百万次迭代后内存使用量保持不变。
使用节点版本:0.10.29与--expose-gc
对于可能发生的事情以及如何避免内存泄漏的任何见解都将非常感激。
测试代码:
(function() {
var MAX_ITER_COUNT, MEGABYTE, dumpMem, gc, iterCount, noop, peakMem, test2;
iterCount = 0;
MAX_ITER_COUNT = 1000 * 1000;
peakMem = 0;
MEGABYTE = 1024 * 1024;
noop = function() {};
dumpMem = function() {
var currentMem;
currentMem = Math.round(process.memoryUsage().heapUsed / MEGABYTE);
if (currentMem > peakMem) {
peakMem = currentMem;
}
return console.log("" + iterCount + " - memory is: " + currentMem + "/" + peakMem + " MB");
};
gc = function() {
return global.gc();
};
process.on("uncaughtException", function(err) {
return console.log("Unhandled exception! ", err, err.stack);
});
test2 = function() {
var e;
iterCount++;
try {
/*
Load a module that has a syntax error to create mem leak, and ignore exception
*/
require("./SyntaxError");
} catch (_error) {
e = _error;
}
gc();
dumpMem();
return setTimeout(test2, 0);
};
test2();
}).call(this);
和SyntaxError.js:
(function() {
'use strict';
/* y does not exist, and results in exception*/
var x;
x = y;
}).call(this);
答案 0 :(得分:2)
似乎这是一个节点错误。我可以通过在语法错误.js中放置SyntaxError.js 的主体周围的try / catch来解决它。我的测试,从上面简化:
MEM-泄漏bug.js:
for (i=0; i<1000000; i++) {
try {
require('./mem-leak--error.js');
}
catch (e) { }
if (i % 1000 === 0) {
global.gc();
console.log(i, process.memoryUsage().heapUsed/1e6|0, process.memoryUsage().heapTotal/1e6|0);
}
}
MEM-泄漏 - error.js:
注意:必须是catch块中的显式返回,否则这也会泄漏内存
// throw an undefined variable exception
try {
return x;
}
catch(e) {
return;
}
没有try-catch,它会泄漏内存:
% node --expose-gc ar/mem-leak-bug.js
0 1 5
1000 2 14
2000 2 14
3000 3 14
4000 3 23
5000 3 23
6000 4 24
使用SytaxError中的try-catch,它不会:
% node --expose-gc ar/mem-leak-bug.js
0 1 5
1000 1 7
2000 1 7
3000 1 7
4000 1 7
5000 1 7
6000 1 7
7000 1 7
8000 1 7