nodejs , socket.io simple code memory leak

13.9k Views Asked by At

i wrote code bellow using nodejs And socket.io for a simple socket application (just connect and disconnect ), for about 50 user memory usage not change to much , but for up to 300 user and after one hour , memory usage just grow up ( near 300MB for server.js proccess and grows by time pass ) , it's look like that nodejs don't release memory.

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);
    });
});

am i doing some thing wrong ?!

Edit

14 hours after starting file with forever enter image description here

300 open sockets And About 500MB of memory usage that is related to my nodejs proccess.

Edit

After 16 Hours , 300 Connected Sockets enter image description here After process stopped. enter image description here

ٍEdit

loot at my new code please.

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];
        });
});

i am trying this with 1000 connected user ( another server is simulate user requests and open sockets )

memory usage before start :100MB , after 5 minutes and 1000 stable open connections : 400MB

3

There are 3 best solutions below

3
On

The code looks fine. Your proposed memory leak is almost certainly not in the part of the code you have shared.

This isn't pertinent to your main question, but if you just wish to list the number of connected sockets, you should use an integer counter instead of calling Object.keys() on the sockets object, like this:

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 );
    });
});
5
On

V8 is lazy when it comes to freeing up unused memory, so it may look like a memory leak when it is actually just V8 not running its garbage collector. To see if this is the case, run your process with the --expose-gc flag set e.g.

node --expose-gc yourscript.js

And force manual garbage collection on an interval (I used 30 second interval).

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

I have had similar problems with socket.io

So what I do to resolve this is:

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 {}
    }
});

If you are thinking about why am I checking that sever is disconnected manually instead of relying on socket.on('disconnect'). The reason is, Socket.io Client has to inform the server that it will disconnect its self before breaking the connection. But If the Client's internet goes down OR incases the Socket.io Client is running on some platform outside Browser, let's say JAVA, Dart, etc, unless you program APP to manually inform the server to disconnect, Socket.io_Server will never find out that it's client got disconnected. Not Surprisingly socket.state will also return you 'connected'.

So to overcome that sever has to look for its clients manually.