收集所有存在內存泄漏的所有case。哪怕一個字節(jié)也不放過。
Case1:無限制增長的數(shù)組
varleakArray=[];exports.leak=function(){leakArray.push("leak"+Math.random());};
這個大概是最常見的內存泄漏案例。只要變量leakArray不被回收,內存就有可能無限上漲,且不被回收。
解決方案
確認你push元素的數(shù)組對象是可以隨著作用域執(zhí)行結束回收。
Case2:無限制設置屬性和值
這個情形在緩存對象中經(jīng)常出現(xiàn):
_.memoize=function(func,hasher){varmemo={};hasher||(hasher=_.identity);returnfunction(){varkey=hasher.apply(this,arguments);return_.has(memo,key)?memo[key]:(memo[key]=func.apply(this,arguments));};};
memoize方法主要是用來解決昂貴CPU耗用的js運算的。它十分有用。但是在后端使用的時候要十分小心。因為memo對象是不會回收的,每次的參數(shù)不同都會在這個對象上添加屬性和值。
這個案例中,memo對象被當作了緩存來使用,一直無法得到回收。
解決方案
關于如何規(guī)避這種無限制緩存的問題,請移步到我另開的帖子中看解決方案:http://cnodejs.org/topic/4fafc843e7656c60680306f9
Case3:任何模塊內的私有變量和方法均是永駐內存的
(function(exports,require,module,__filename,__dirname){varcircle=require('./circle.js');console.log('The area of a circle of radius 4 is '+circle.area(4));exports.get=function(){returncircle();};});
任意編寫的模塊文件中,均會在頭和尾部上添加字符串,以形成閉包,然后在require的過程中被調用一次,并且將exports對象存儲在內存中,直到進程退出才會回收。
這個案例中,只是內存不會回收,但一般不會造成內存泄漏。需要注意的是私有變量不要通過exports上的方法為其添加內存占用。
第一個案例其實就是由于這個原因造成的。
第四個案例來自于http://cnodejs.org/topic/4fcd020be5e72c25180032e5。
//OOM測試for(vari=0;i<100000000;i++){varuser={};user.name='outmem';user.pass='123456';user.email='outmem[@outmem](/user/outmem).com';}
這段代碼最主要的原因在于循環(huán)太大,直接內存分配到超過v8內存限制數(shù)量。由于JavaScript事件循環(huán)的執(zhí)行機制,這段代碼沒有機會進入下一個事件循環(huán)。用setInterval和setTimeout可以進入下一個循環(huán)。但是不推薦用setInterval和setTimeout。
在Node下有一個特殊的方法,process.nextTick();
for(vari=0;i<100000000;i++){process.nextTick(function(){varuser={};user.name='outmem';user.pass='123456';user.email='outmem[@outmem](/user/outmem).com';});}
不過這樣的效率可能不夠好。因為每次都沒有效利用好一次循環(huán)。
一個建議是,一次事件循環(huán),不要超過10ms。太長時間的事件循環(huán),不僅會存在oom的風險,還會阻塞后續(xù)IO的啟動。
http://alinode.aliyun.com/blog/37