Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory Leak with socket.io + node.js

I appear to have a memory leak with my Node.js application. I built it quickly, and my JavaScript isn't too strong, so this might be easy.

I've done some heap dumps on it, and it's the String object? leaking memory, at the rate of about 1MB every 5 minutes. I expanded String, and it's actually String.Array?

Heap stack: enter image description here

#!/usr/local/bin/node  var port = 8081;  var io = require('socket.io').listen(port), sys = require('sys'), daemon = require('daemon'), mysql = require('mysql-libmysqlclient');  var updateq = "SELECT 1=1"; var countq = "SELECT 2=2";  io.set('log level', 2);   process.on('uncaughtException', function(err) {   console.log(err); });  var connections = 0;  var conn = mysql.createConnectionSync(); dbconnect();  io.sockets.on('connection', function(client){    connections++;   client.on('disconnect', function(){ connections--;  })  });  process.on('exit', function () {     console.log('Exiting');     dbdisconnect(); });  function dbdisconnect() {      conn.closeSync(); }  function dbconnect() {     conn.connectSync('leet.hacker.org','user','password'); }   function update() {     if (connections == 0)         return;     conn.query(updateq, function (err, res) {       if (err) {         dbdisconnect();         dbconnect();         return;       }       res.fetchAll(function (err, rows) {         if (err) {           throw err;         }         io.sockets.json.send(rows);       });     }); }  function totals() {     if (connections == 0)         return;         conn.query(countq, function (err, res) {           if (err) {         // Chances are that the server has just disconnected, lets try reconnecting         dbdisconnect();         dbconnect();             throw err;           }           res.fetchAll(function (err, rows) {             if (err) {               throw err;             }         io.sockets.json.send(rows);           });         });  }  setInterval(update, 250); setInterval(totals,1000);  setInterval(function() { console.log("Number of connections: " + connections); },1800000);      daemon.daemonize('/var/log/epiclog.log', '/var/run/mything.pid', function (err, pid) {     // We are now in the daemon process     if (err) return sys.puts('Error starting daemon: ' + err);      sys.puts('Daemon started successfully with pid: ' + pid);   }); 

Current version

function totals() {          if (connections > 0)         {                 var q = "SELECT query FROM table";              db.query(q, function (err, results, fields) {             if (err) {                     console.error(err);                     return false;             }              for (var row in results)             {                     io.sockets.send("{ ID: '" + results[row].ID + "', event: '" + results[row].event + "', free: '" + results[row].free + "', total: '" + results[row].total + "', state: '" + results[row]$                     row = null;             }               results = null;             fields = null;             err = null;             q = null;             });     } } 

Still leaking memory, but it seems only on these conditions:

  • From startup, with no clients -> Fine
  • 1st client connection -> Fine
  • 2nd client (even with the 1st client disconnecting and reconnecting) -> Leaking memory
  • Stop all connections -> Fine
  • 1 new connection (connections = 1) -> Leaking memory
like image 364
giggsey Avatar asked Jun 24 '11 16:06

giggsey


People also ask

Does socket.io use a lot of memory?

Basic usage of socket.io causes incremental memory usage (about +4mb every second). Even when nothing is transmitting.

How do I resolve a memory leak issue in node JS?

A quick way to fix Node. js memory leaks in the short term is to restart the app. Make sure to do this first and then dedicate the time to seek out the root cause of the memory leak.

Is Nodejs memory safe?

They are absolutely NOT SAFE.

How much data can socket.io handle?

As of v3, socket.io has a default message limit of 1 MB. If a message is larger than that, the connection will be killed.


1 Answers

Do yourself a favour and use node-mysql, it's a pure javascript mysql client and it's fast. Other than that, you should be using asynchronous code to stop IO being blocked whilst you're working. Using the async library will help you here. It has code for waterfall callback passing among other things.

As for your memory leaking, it probably isn't socket.io, although I haven't used it in a few months, I have had many thousands of concurrent connections and not leaked memory, and my code wasn't the best either.

Two things, however. Firstly your code is faily unreadable. I suggest looking into properly formatting your code (I use two spaces for every indentation but some people use four). Secondly, printing the number of connections every half an hour seems a little silly, when you could do something like:

setInterval(function() {   process.stdout.write('Current connections: ' + connections + '     \r'); }, 1000); 

The \r will cause the line to be read back to the start of the line and overwrite the characters there, which will replace the line and not create a huge amount of scrollback. This will help with debugging if you choose to put debugging details in your logging.

You can also use process.memoryUsage() for quickly checking the memory usage (or how much node thinks you're using).

like image 81
Robin Duckett Avatar answered Sep 28 '22 09:09

Robin Duckett