//显示内存使用情况
var showMem = function(){
var mem = process.memoryUsage();
var format = function(bytes){
return (bytes / 1024 / 1024).toFixed(2) + ' MB';
};
console.log('process: heapTotal '+format(mem.heapTotal) +
' heapUsed '+format(mem.heapUsed) + ' rss ' + format(mem.rss));
console.log("-------------------------------------------------------");
}
//申请内存
var useMem = function(){
var size = 20*1024*1024;
var arr = new Array(size);
for( var i=0; i<size; i++){
arr[i] = 0;
}
return arr;
}
var total = [];
for( var j = 0; j<5; j++){
showMem();
total.push(useMem());
}
//清理内存
for( var i=0; i<total.length; i++){
total[i] = undefined;
}
total = undefined;
console.log("清理内存完毕");
setInterval(showMem, 5000);
垃圾回收不及时,v8引擎的垃圾回收机制问题
@jerrywu55 我放在哪里放了20分钟,都不回收内存,真不知道是什么回事
@wf744 并不是放了一段时间v8就回收内存的,是随着内存的使用,而扫描内存的使用情况,然后然后在适当的时机去回收。具体可以看一下《深入浅出Node.JS》,里面有很详细的介绍
@crystaldust 这个例子就是《深入浅出Node.JS》里面的,只不过书里面只说了内存是如何分配的,却没有说到上面这个例子的内存回收; 因为我的服务器遇到了一个问题就是RSS内存一直往上涨,一直涨到几G,但是堆内存是正常的,能正常回收和正常分配,所以想从最简单的例子入手,却发现最简单的例子(上面的代码),也不会自动回收
–trace_gc 加上看看就知道了
内存一直没变化,是不做gc的,稍微变动下内存,立马释放了。。。
@fantasyni 如何变动?我增加了以下这样的代码18秒后继续申请,内存继续上涨,没有任何降低的趋势
setTimeout(function(){var aaa = new Array(20000); console.log(“变动内存”);}, 18000);
改成死循环,然后看会不会OOM。
console.log(“清理内存完毕”); setInterval(showMem, 5000);
改成
setInterval(function() {
useMem();
showMem();
}, 5000);
node -trace_gc foo.js
这方法有用,能回收了,但是为什么不动就不回收呢,这个就很奇怪
因该 =null 吧
不懂。。
@wf744 应该是因为做完用undefined赋值这一步之后,因为并没有继续使用内存,所以v8并没有扫描内存的使用情况,也就无法触发回收;或者有扫描,但是v8认为还不至于触发回收。
用10楼仁兄的方法,因为有继续分配内存,所以v8会扫描内存并在适当的时机触发回收。 我打印的结果是这样的,其中status是触发了回收时打印的标记:
process: heapTotal 6.32 MB heapUsed 3.46 MB rss 13.79 MB
-------------------------------------------------------
process: heapTotal 169.32 MB heapUsed 163.78 MB rss 174.73 MB
-------------------------------------------------------
process: heapTotal 330.32 MB heapUsed 323.32 MB rss 335.45 MB
-------------------------------------------------------
process: heapTotal 490.34 MB heapUsed 483.34 MB rss 495.46 MB
-------------------------------------------------------
process: heapTotal 650.36 MB heapUsed 643.34 MB rss 655.47 MB
-------------------------------------------------------
清理内存完毕
stats!
process: heapTotal 970.40 MB heapUsed 963.41 MB rss 975.73 MB
-------------------------------------------------------
process: heapTotal 1130.42 MB heapUsed 1123.46 MB rss 1135.73 MB
-------------------------------------------------------
process: heapTotal 331.31 MB heapUsed 323.36 MB rss 335.85 MB
-------------------------------------------------------
stats!
process: heapTotal 491.33 MB heapUsed 483.39 MB rss 495.85 MB
-------------------------------------------------------
@wf744 你的代码并没有问题,你的理解也没有问题。走到最下面 你对total[i]=undefined是会进行垃圾回收的。
为什么这里没有显示出来,我的解释如下:
- 因为你在for(var j=0;j<5;j++){} 这里进行申请堆内存,你5次循环后申请的堆内存大约在810M左右。并没有触发到V8的内存上限(1400MB左右),常驻在老生代,因此不触发Full GC; ====> 你可以通过把循环改大,比如到50次,这个时候会一直申请堆内存,直到分配不了而出错
2 当你只有5次申请内存后,进入下面的清理内存行为,即你的第2个循环。for(var i=0;i<total.length;i++){},是进行老生代的mark行为,也就是标记死亡对象的行为,要老生代进行sweep行为或者compact行为,才能真正意义的释放老生代的堆内存空间。而你要触发这个行为,就是下一次申请老生代堆内存的行为;类似再一次执行你的useMem()方法。 ====> 你可以通过在第一个循环(第1个循环,不是第2个循环),修改为这样的代码 然后你执行node --trace_gc index.js 会得到下面的结果,就验证了你的total[i]=undefined是有释放内存的效果的、 最后50次执行完,可以看到如下效果 这个时候,就清理剩下300M左右的堆内存了。