nodejs,socket.io简单代码内存泄漏

时间:2015-06-10 20:32:44

标签: node.js memory-leaks socket.io

我使用nodejs和socket.io编写代码,用于简单的套接字应用程序(只需连接和断开连接),大约50个用户内存使用量不会变化太多,但对于最多300个用户和一小时后,内存使用只是长大(对于server.js进程接近300MB并且随着时间的推移而增长),看起来nodejs不会释放内存。

var server = require('http').createServer();
var io = require('socket.io')(server);
var port = 9090;
var sockets = {};

server.listen(port, function () {
    console.log('Server listening at port ', port);
    //timer and logs are not problem , i tested it before.
    setInterval(function(){
      console.log(Object.keys(sockets).length+' Online Devices At '+Date());
    }, 1000 * 60 * 1); 
});

io.on('connection',function(socket){
    sockets[socket.id]={id:socket.id};
    console.log('connected '+socket.id + ' count ' + Object.keys(sockets).length);
    socket.on('disconnect', function (data) {
        delete sockets[socket.id];
        console.log('disconnected '+socket.id+ ' count ' +Object.keys(sockets).length);
    });
});

我做错了什么?!

修改

使用forever启动文件后14小时 enter image description here

300个开放套接字和大约500MB的内存使用量与我的nodejs进程相关。

修改

16小时后,300个连接插座 enter image description here 过程停止后。 enter image description here

修改

请抓住我的新代码。

var server = require('http').createServer();
var io = require('socket.io')(server);
var port = 90;
var counter = 0;
var clients = {}
server.listen(port, function () {
        console.log('Server listening at port ', port);
});
io.on("connection",function(socket){
        clients[socket.id] = socket;
        counter++;

        socket.on('disconnect', function (data) {
                counter--;
                delete clients[socket.id];
        });
});

我正在尝试使用1000个连接用户(另一个服务器模拟用户请求和打开套接字)

启动前的内存使用量:100MB, 5分钟后和1000个稳定的开放连接:400MB

3 个答案:

答案 0 :(得分:10)

V8在释放未使用的内存时很懒,所以当它实际上只是V8没有运行其垃圾收集器时,它可能看起来像是内存泄漏。要查看是否是这种情况,请使用--expose-gc标志设置运行您的流程,例如

node --expose-gc yourscript.js

并且间隔强制手动垃圾收集(我使用30秒间隔)。

setInterval(function(){
  global.gc();
  console.log('GC done')
}, 1000*30);

答案 1 :(得分:0)

代码看起来很好。您提议的内存泄漏几乎肯定不在您共享的代码部分中。

这与您的主要问题无关,但如果您只想列出已连接套接字的数量,则应使用整数计数器,而不是在Object.keys()对象上调用sockets,例如这样:

var express = require('express');
var app     = express();
var server  = require('http').createServer(app);
var io      = require('socket.io')(server);

var port = 9090;
var connectedSockets = 0;
var sockets = {};

server.listen(port, function () {
    console.log('Server listening at port ', port);
    //timer and logs are not problem , i tested it before.
    setInterval(function(){
      console.log(connectedSockets + ' Online Devices At ' + Date());
    }, 1000 * 60 * 1); 
});

io.on('connection',function(socket){
    if (!sockets[socket.id]) connectedSockets++;
    sockets[socket.id]={ id: socket.id };
    console.log('connected ' + socket.id + ' count ' + connectedSockets);
    socket.on('disconnect', function (data) {
        delete sockets[socket.id];
        connectedSockets--;
        console.log('disconnected ' + socket.id + ' count ' + connectedSockets );
    });
});

答案 2 :(得分:0)

socket.io也有类似的问题

所以我要解决的是:

io.on('connection', function (socket) {
    socket.on('disconnect', function (data) {
        destroy();
    });

    var alive = Date.now();
    socket.on('am_alive', (data) => {
        alive = Date.now();
    }); // client tell the server that it is alive

    const intv = setInterval(() => {
        if (Date.now() > alive + 20000) {
            //sever checks if clients has no activity in last 20s
            destroy();
            clearInterval(intv);
        }
    }, 10000);

    function destroy() {
        try {
            socket.disconnect();
            socket.removeAllListeners();
            socket = null; //this will kill all event listeners working with socket
            //set some other stuffs to NULL
        } catch {}
    }
});

如果您正在考虑为什么我要检查服务器是手动断开连接,而不是依靠socket.on('disconnect')。 原因是,Socket.io Client必须在断开连接之前通知服务器它将断开自身连接。但是,如果客户端的Internet中断或Socket.io客户端在浏览器之外的某个平台上运行,则可以说JAVA,Dart等,除非您对APP进行编程以手动通知服务器断开连接,否则Socket.io_Server将永远不会发现它的客户端已断开连接。毫不奇怪,socket.state也会使您“连接”。

因此,要克服这一点,服务器必须手动寻找其客户端。