疑似nodejs内存泄露的一种情况,websocket连接断开后,仍然占有一定内存。
发布于 1 个月前 作者 bingino 643 次浏览 来自 问答

利用github上ws 包 https://github.com/websockets/ws 实现的服务端,在并发测试时候,写了一些脚本做测试。 3万client端连接尚服务端,然后断开。在gc 回收稳定之后,内存较初始要高。且连接数越多,内存占用会越多。 github上提出的问题。 https://github.com/websockets/ws/issues/804

不知道这种情况是否正常?为什么会有这种内存占用的情况呢?

14 回复

我WIN10 NODEJS 6.9.4 最多200M内存,断开所有连接一直都是停留在190M,然后新建立一个连接上来,就降到了50M左右,断开连接,过几分钟就变成了25M

用内存泄露工具跑了下,没有发现有什么无法回收的引用泄露

图一是保持10K连接的内存,最大内存开销是Object,个数有3万多个,内存对象定位是ws.clients,这个是用来保存在线连接的一个数组.看引力图也没有发现非常长的对象引用.应该不会导致内存泄露. 未命名-1.jpg

图二是断开所有客户端连接以后,Object对象也减少到了1000左右,内存占用也从70多M,降到了7M. untitled2.png untitled3.png

@sunwukong2012 请问这个是什么工具监控node内存的,不胜感激

@sunwukong2012 被拿来用了哇…好开心

请问你用那个脚本进行测试。@sunwukong2012

如果回调函数不进行回调,不知道会否出现问题呢? 比如

					 clientsMap.hasWsConnect(userId, function() {
								/*保存APP与Websocket长连接到clients集合当中*/
								clientsMap.addGallery(userId, ws);
							});
							
							
							exportrs.hasWsConnect(userId,fun){
							if(clients.has(userId){
							fun();  //执行回调
							}else{
							//不执行回调
							}
							}

不知道这样会否出现问题? @sunwukong2012 @hyj1991

@bingino @kimown
用的easy-monitor,来监控的. 挺好用的. 工具的原文在这里: https://cnodejs.org/topic/58d0dd8b17f61387400b7de5

不进行回调应该不会导致内存泄露.

我觉得是你的clients集合当中的问题

如果你再用户断线以后,没有及时把断线用户清除出clients集合,那么这个断线的用户的ws对象就会一直被clients集合引用,这样肯定不会被GC回收掉.

重复的这样以后就会内存泄露了.

你先用这个工具跑一下,看看是哪些对象一直被引用,从而导致释放不掉.

@hyj1991 谢谢开发那么方便的工具,非常直观也简单,这个比v8-profiler好用多了,用浏览器打开,数据量非常大,打开的时候经常卡个半天,查找起来也确实麻烦.还不能线上观察.

你误会啦,我指的是你用来测试的服务端和客户端脚本是哪个,而不是工具?因为你测试的结果和我测试结果出入较大,能否提出你测试的脚本?

@bingino 我复制的你在github上回复的代码测试的,不过我一个脚本也就只能跑10K连接,多了就报错,socket hang up.

不过可以开2个进程来跑20K,测试结果也差不多.

client.js

var WebSocket = require(‘ws’);

function cerateclient(){ var ws = new WebSocket(“ws://localhost:8001/”); ws.onopen = function() { ws.send(‘connnect’); };

ws.onmessage = function(evt) { //console.log(evt.data); }; }

for(var i =0 ; i < 10000; i++){ cerateclient(); }

server.js

const easyMonitor = require(‘easy-monitor’); easyMonitor(‘test’);

const WebSocket = require(‘ws’);

const wss = new WebSocket.Server({ host:‘127.0.0.1’, perMessageDeflate: false, port:8001 });

wss.on(‘connection’, function connection(ws) { ws.on(‘message’, function incoming(message) { //console.log(‘received: %s’, message); }); ws.send(‘something’); });

v8的垃圾回收是惰性的,你可以打上 --expose-gc 然后在代码里用global.gc()试试

@Equim-chan 是的,内存会一直占用,等你需要用到更大内存时候就开始回收,和linux内存管理差不多.

好的,谢谢两位。@Equim-chan @sunwukong2012

咨询一下,我在使用easy-monitor。按照教程所讲。安装并引入了包。使用node命令启动程序时候,报出夜莺成功连接127.0.0.1:26666 success 1495795000(1).png 但我在谷歌浏览器打开连接 http://127.0.0.1:12333 时候,提示拒绝连接请求。这是我的projectname 处出现问题了么? /path/projectA/bin/main.js 以这路径为例,我的project name直接写projectA这样可以么? @sunwukong2012 @hyj1991

@bingino 有什么错误信息么,26666 只是tcp通信连上了 而且你要知道,它能分析的只有堆内内存,你纠结的 rss-heapTotal 部分因为不走 v8 的 handle 引用管理,没法解析 实在想弄明白,可以试试看 alinode~

来自酷炫的 CNodeMD

回到顶部