大家好,一直想用node.js的Net模块来实现一个高密集IO和并发的“中转服务器”,但是发现内存泄漏特别严重; 我用最原始的简单Socket测试,发现服务器内存也是一样的疯狂增长,具体如下所示: 服务器主类Application.js:
- var fs = require(‘fs’);
- Application =
- {
-
mServerApp : null,
-
StartLocalListen:function()
-
{
-
this.mServerApp.listen(15002, "127.0.0.1");
-
console.log("listen on port="+15002);
-
},
-
CreateTCPServer:function()
-
{
-
this.mServerApp = require('net').createServer();
-
this.mServerApp.on('connection', function(socket)
-
{
-
socket.on('data', function(data){ delete data;data=null; });
-
socket.on('close', function(){
-
socket.end();
-
socket.destroy();
-
delete socket;
-
socket = null;
-
});
-
socket.on('error', function(){ });
-
});
-
},
-
Start:function()
-
{
-
this.CreateTCPServer();
-
this.StartLocalListen();
-
console.log("start ");
-
}
- };
- var path = require(‘path’);
- var pidfile = path.join(__dirname, ‘app.pid’);
- fs.writeFileSync(pidfile, process.pid);
- process.on(‘SIGTERM’, function() {
- if (fs.existsSync(pidfile))
-
fs.unlinkSync(pidfile);
- process.exit(0);
- });
- process.on(‘uncaughtException’, function (err) {
- console.log(err);
-
//process.exit(0);
- });
- Application.Start();
服务器的测试代码就是这么简单,监听客户端连接,数据和关闭消息而已。 而客户端就是简单创建连接(100个),然后随意发送数据,关闭而已。 现在发现每次模拟多个连接发送数据,断开之后,服务器的内存都会增加,且永远不释放,且每次有新连接进来就增加。 好神奇的内存泄漏啊,请各位大神帮忙看看,太感谢了。
请前后各用三个反引号将代码括起来。 请将客户端测试代码一起发上来。 观察到的内存最大值是多少?
客户端的测试代码非常简单:
- Application =
- {
-
Start:function()
-
{
-
for (var i=0; i<1000; i++)
-
{
-
var net = require('net');
-
var mSocket = new net.Socket();
-
mSocket.on('connect', function() { mSocket.write("dhdhfkhfhdhd"); });
-
mSocket.on('data', function(message) { delete message; });
-
mSocket.on('close', function() { mSocket.destroy(); });
-
mSocket.connect(15002, "127.0.0.1");
-
console.log("create "+i);
-
}
-
}
- };
- Application.Start();
测试结果: 1:服务器启动的时候,9M左右 2:客户端启动一次,服务器内存增加到18M 3:客户端启动多次,服务器内存一直增加,且无客户端时,经过1晚上,内存为释放
最前和最后加三个反引就行了,不用每行都加。 那你测得的最高占用是多少? 如果会回落,证明是不存在泄露的。代码虽然不雅观,但目测是不存在泄露问题的。 V8的GC貌似是智能回收,内存够用的情况下应该是很长时间后才会被激发。
@klesh 谢谢klesh兄,我目前没有测试过最高会多少;但是只要有新客户端连接,内存就会增加(我的测试,每次都会创建1000个客户端链接,在断开,内存都会增长十M);
目前没有发现会回收, 我把服务器空置12小时,那块增长的内存还是不会释放。 而对于我们搞C/C++服务器的要求,一个字节都不要泄漏,而现在把人能泄死,这个问题Klesh兄也可以测试一下,就是一个简单Socket链接而已。
error为什么不加删除socket的代码
@AntSworD兄,加不加还是都会内存泄漏,只增加不减少;这样子怎么可能用来做服务器啊
内存泄露是指进程消耗内存不断增长,最终导致没有可用资源。你描述的是新加连接才增加,仅仅是不会下降而已。V8的回收机制并不是像普通的回收一样,用完就释放。仅仅在他需要释放时候才会触发gc,你刻意的去gc可能导致服务响应变慢。 建议你看下nodejs入门之类的,关于V8的介绍。
@guanzhongdaoke 那你可以试一下强制GC,看内存会不会回落。启动程序时加上 --expose-gc 然后在应用中调用gc()就可以强制回收了。 你这个都是局部变量,delete 不 delete 有没有 set null 都不会有影响的。也不存在内存队列,照理是没问题的。
@klesh 兄,昨天试过强制GC了,没有作用,内存还是会增加。 如果内存只增加不减少,那真的是没办法用在大型系统
@haozxuan 兄,不管我们用c/c++还是JAVA做Server,都要求不能有内存泄漏,用c的话,以前都是确保一个字节都没有泄漏的。 每次新链接都会增加,如果用在我们的大型中转服务器上面,时刻都有链接的建立和断开,且要求都是7*24稳定,不只增加不下降肯定撑不住啊。
这个问题,困扰我好久了
从你的代码看就知道你对GC一点不清楚病疾乱投医了。
又是delete data
又是data = null
,这两行代码都不需要,而且你不知道JavaScript中delete 变量名
压根就是无效的语句吗?那只能用来delete obj.property
。
真正的原因是……GC不会实时回收,你才用了18M而已,有什么必要立即执行?
你可以node --expose-gc app.js
然后在代码中写个每隔十秒GC一次:
setInterval(function () { //请勿在生产环境加这种代码
console.log("Before:",process.memoryUsage());
gc();
console.log(" After:",process.memoryUsage());
},10000);
就会发现内存还是回收了(heapUsed
)
或者像JVM那样,设置个minHeap、maxHeap之类的东西,也有: http://stackoverflow.com/questions/30252905/nodejs-decrease-v8-garbage-collector-memory-usage
@JexCheng 兄说的有道理,思维可能没有转化过来。 确实之前多年主要用c/c++来做服务器,对于每一个字节都需要自己控制不泄漏; 现在发现时代变化太快,我们也需要拥抱新型优秀的语言来做服务器,就是用node.js时感觉内存没释放挺惊讶,也是对他了解不够的原因。不过只有把这些全部搞明白了,才敢真正用在线上环境~~~~ 谢谢大家的指导。
@guanzhongdaoke V8引擎和node.js目前都已经相当成熟,本身不太可能会出现泄露。出名的类库反正我用的还没有发现有泄露问题的。写的过程注意模块级变量/全局变量的使用。而局部变量都是安全的。试过一回内存不跌是有一个模块级的内存异步队列,入太快,出太慢导致。搞了我三天才找出问题。所以NODE.JS对于从同步转向异步的程序员来讲,这个异步才是最大的坑。V8的GC我没仔细研究,但是LINUX的内存管理机制是释放了系统会当作缓存,不会变成FREE的状态,安卓的内存管理同样如此。 另外NODE.JS中,你引用包A和包B,包A引用又引用包B,那么,内存中是会有两个包B的!这个有点让人郁闷。所以跑NODE.js,内存还是要多些。 c/c++我还没具体做过东西,但就像是 .NET 这玩意,开发效率相对node.js都是极低的!同样的项目,搞不好node.js在线上迭代了,c/c++还在debug空指针的问题。 相对 ror 当年还要定时重启进程的情况,node.js真是好太多了。你不知道当年 ror 内存泄露的问题那叫一个让人难堪。node.js 当可放心使用。