33 votes

Fuite de mémoire avec socket.io + node.js

Il semblerait que j'ai une fuite de mémoire avec mon application Node.js. Je l'ai construite rapidement, et mon JavaScript n'est pas trop fort, donc cela pourrait être facile.

J'ai fait quelques captures d'écran de la mémoire, et c'est l'objet String object qui fuit en mémoire, à un rythme d'environ 1 Mo toutes les 5 minutes. J'ai élargi String, et c'est en fait String.Array?

Pile de mémoire : image

#!/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('Sortie');
    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) {
        // Il est probable que le serveur vient de se déconnecter, essayons de nous reconnecter
        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("Nombre de connexions : " + connections);
},1800000);

  daemon.daemonize('/var/log/epiclog.log', '/var/run/mything.pid', function (err, pid) {
    // Nous sommes maintenant dans le processus du démon
    if (err) return sys.puts('Erreur lors du démarrage du démon : ' + err);

    sys.puts('Démon démarré avec succès avec PID : ' + pid);
  });

Version actuelle

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

Toujours une fuite de mémoire, mais cela semble se produire uniquement dans ces conditions :

  • Depuis le démarrage, sans clients -> Bon
  • 1ère connexion client -> Bon
  • 2ème client (même si le 1er client se déconnecte et se reconnecte) -> Fuite de mémoire
  • Arrêt de toutes les connexions -> Bon
  • 1 nouvelle connexion (connections = 1) -> Fuite de mémoire

1 votes

7 votes

connectSync :(

0 votes

Vous mentionnez avoir modifié String pour contenir String.Array, et même nous indiquer cela dans votre capture d'écran de mémoire, mais je ne vois rien dans votre code qui utiliserait cela, ni ce que vous avez réellement fait pour créer String.Array.

5voto

Robin Duckett Points 1417

Faites-vous une faveur et utilisez node-mysql, c'est un client mysql javascript pur et rapide. Autre que ça, vous devriez utiliser du code asynchrone pour éviter que l'entrée-sortie soit bloquée pendant que vous travaillez. L'utilisation de la bibliothèque async vous aidera ici. Elle contient du code pour le passage de rappel en cascade entre autres choses.

Quant à votre fuite de mémoire, ce n'est probablement pas socket.io, bien que je ne l'ai pas utilisé depuis quelques mois, j'ai eu des milliers de connexions concurrentes et je n'ai pas eu de fuite de mémoire, et mon code n'était pas le meilleur non plus.

Cependant, deux choses. D'abord, votre code est assez illisible. Je vous suggère de vous pencher sur la mise en forme correcte de votre code (j'utilise deux espaces pour chaque indentation mais certaines personnes en utilisent quatre). Ensuite, afficher le nombre de connexions toutes les demi-heures semble un peu idiot, quand vous pourriez faire quelque chose comme :

setInterval(function() {
  process.stdout.write('Connexions actuelles : ' + connexions + '     \r');
}, 1000);

Le \r provoquera le retour à la ligne pour être lu depuis le début de la ligne et écraser les caractères là-bas, ce qui remplacera la ligne et n'alourdira pas énormément le défilement. Cela aidera pour le débogage si vous choisissez d'inclure des détails de débogage dans vos journaux.

Vous pouvez également utiliser process.memoryUsage() pour vérifier rapidement l'utilisation de la mémoire (ou la quantité de mémoire que node pense que vous utilisez).

1 votes

Merci. Bien qu'on pense actuellement qu'il s'agisse d'une fuite de mémoire dans socket.io - Voir : github.com/LearnBoost/socket.io/issues/299

0voto

imperium2335 Points 1631

Cela pourrait-il être lié au fait que le tableau des clients connectés ne se vide pas correctement lorsque qu'un client se déconnecte? La valeur du tableau est définie sur NULL plutôt que d'être supprimée du tableau.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X