2011-06-24 100 views
32

我似乎有我的節點應用程序內存泄漏。我很快就構建了它,並且我的JavaScript不太強大,所以這可能很容易。內存泄漏與socket.io + node.js

我已經做了一些堆轉儲,它是字符串'對象'?內存泄漏,每5分鐘約1MB。我擴展了String,實際上是String.Array?

堆棧: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); 
    }); 

當前版本

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

不過內存泄露,但似乎只有這些條件:

  • 從啓動時,有沒有客戶端 - >精細
  • 第一客戶端連接 - >精細
  • 第二客戶端(甚至與第一客戶端斷開和重新連接) - >泄漏存儲器
  • 停止所有連接 - >精細
  • 1新的連接(連接= 1) - >漏水內存
+1

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

+7

'connectSync' :( – Raynos

+0

你提到你修改後的String來包含String.Array,甚至將我們指向你的內存快照,但我沒有看到你的代碼中會使用這個,也沒有看到你實際做了什麼來創建String.Array – Matt

回答

5

幫你一個忙,使用node-mysql,這是一個純粹的javascript mysql客戶端,它的速度很快。除此之外,您應該使用異步代碼在工作時阻止IO被阻塞。使用async庫將幫助你在這裏。它有瀑布回調傳遞代碼等。

至於你的內存泄漏,它可能不是socket.io,雖然我沒有在幾個月內使用它,但我有成千上萬的併發連接,並沒有泄漏內存,而且我的代碼不是最好的。

但是有兩件事。首先你的代碼是難以理解的。我建議尋找正確格式化你的代碼(每個縮進使用兩個空格,但有些人使用四個)。其次,打印連接數每半小時似乎有點傻了,當你可以這樣做:

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

\r會導致線路被讀取回線的起點和覆蓋字符在那裏,它將取代這一行而不會創建大量的回捲。如果您選擇在日誌中添加調試詳細信息,這將有助於調試。

您還可以使用process.memoryUsage()快速檢查內存使用情況(或節點認爲您使用的節點數量多少)。

+1

謝謝。雖然目前認爲它是socket.io中的內存泄漏 - 請參閱:https://github.com/LearnBoost/socket.io/issues/299 – giggsey

0

當客戶端斷開連接時,這可能與連接的客戶端陣列未正確清除有關嗎?數組值被設置爲NULL,而不是從數組中刪除。