2011-06-24 16 views
32

Wygląda na to, że mam przeciek pamięci w aplikacji mojego węzła. Zbudowałem go szybko, a mój JavaScript nie jest zbyt silny, więc może to być łatwe.Wyciek pamięci za pomocą socket.io + node.js

Zrobiłem kilka zrzutów sterty na nim i jest to obiekt "String"? wyciek pamięci, z prędkością około 1 MB co 5 minut. Rozwinąłem String, a właściwie String.Array?

Heap stosu: http://i.imgur.com/ZaBp0.png

#!/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); 
    }); 

Aktualna wersja

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

Wciąż wyciek pamięci, ale wydaje się tylko na tych warunkach:

  • Od startu, bez klientów -> Dobrze
  • 1-ty połączenia klient -> Dobra
  • 2-ty klient (nawet z 1 odłączenia klienta i ponowne podłączenie) -> Wyciek pamięci
  • Zatrzymaj wszystkie połączenia -> Dzieło
  • 1 Nowe połączenie (połączenia = 1) -> Wyciek pamięć
+1

Informacje: http://stackoverflow.com/questions/5733665/how-to-prevent-memory-leaks-in-node-js –

+7

'connectSync' :( – Raynos

+0

Wspomniałeś zmodyfikowany ciąg, aby zawierał String.Array, a nawet wskazują nam na to w twojej migawce pamięci, ale nie widzę w twoim kodzie nic, co by to wykorzystało, ani to, co faktycznie zrobiłeś, by stworzyć String.Array – Matt

Odpowiedz

5

Zrób sobie przysługę i użyj node-mysql, jest to klient javascript z czystym javascriptem i jest szybki. Poza tym, powinieneś używać asynchronicznego kodu, aby zatrzymać IO podczas pracy. W tym celu pomoże biblioteka async. Ma kod wywołania zwrotnego typu waterfall między innymi.

Co do wycieku pamięci, prawdopodobnie nie jest to plik socket.io, chociaż nie korzystałem z niego w ciągu kilku miesięcy, miałem wiele tysięcy równoczesnych połączeń i nie wyciekły pamięci, a mój kod nie był najlepiej albo.

Dwie rzeczy jednak. Po pierwsze, twój kod jest nieczytelny. Sugeruję sprawdzenie poprawnego sformatowania kodu (używam dwóch spacji dla każdego wcięcia, ale niektórzy używają czterech). Po drugie, drukowanie liczby połączeń co pół godziny wydaje się trochę głupio, kiedy można zrobić coś takiego:

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

\r spowoduje, że linia należy czytać z powrotem do początku linii i zastąpienie znaków tam, co zastąpi linię i nie stworzy ogromnej ilości przewijania. Pomoże to w debugowaniu, jeśli zdecydujesz się umieścić szczegóły debugowania w dzienniku.

Można również użyć process.memoryUsage() do szybkiego sprawdzenia użycia pamięci (lub ile węzłów uważa, że ​​używasz).

+1

Dzięki. Chociaż obecnie uważa się, że jest to przeciek pamięci w socket.io - Patrz: https://github.com/LearnBoost/socket.io/issues/299 – giggsey

0

Czy może to być powiązane z połączonymi tablicami klientów, które nie są czyszczone prawidłowo, gdy klient się rozłączy? Wartość tablicy zostanie ustawiona na wartość NULL, a nie zostanie usunięta z tablicy.