2011-02-16 100 views
1

我有一個相當簡單的NodeJS應用程序,它僅僅是一個接受請求並使用可讀性形式(基於https://github.com/arrix/node-readability)解析內容的shell。問題是,我注意到應用程序泄漏內存 - 我已經運行了node --trace-gc,並且內存緩慢地隨着每次請求而建立起來,偶爾的gc通過什麼也不做。NodeJS 0.3.1應用程序泄漏內存

$ node --trace-gc server.js 
Scavenge 2.3 -> 2.3 MB, 1 ms. 
Mark-sweep 3.5 -> 2.9 MB, 2 ms. 
Scavenge 4.4 -> 3.8 MB, 0 ms. 
16 Feb 10:57:51 - Server started on PORT 8000 
Scavenge 5.9 -> 5.0 MB, 2 ms. 
Mark-sweep 5.0 -> 4.2 MB, 3 ms. 
Mark-compact 4.2 -> 4.1 MB, 7 ms. 
Scavenge 5.2 -> 4.7 MB, 1 ms. 
Scavenge 5.5 -> 5.1 MB, 1 ms. 
Scavenge 5.9 -> 5.5 MB, 1 ms. 
Scavenge 7.1 -> 6.3 MB, 2 ms. 
Scavenge 7.8 -> 7.0 MB, 2 ms. 
Mark-sweep 8.5 -> 7.6 MB, 10 ms. 
Scavenge 11.7 -> 9.7 MB, 4 ms. 
Scavenge 12.7 -> 11.2 MB, 5 ms. 
Mark-sweep 14.2 -> 12.4 MB, 21 ms. 
Scavenge 20.5 -> 16.5 MB, 10 ms. 
Scavenge 22.5 -> 19.5 MB, 11 ms. 
Mark-sweep 25.5 -> 22.4 MB, 38 ms. 
Scavenge 36.6 -> 29.6 MB, 25 ms. 
Scavenge 41.6 -> 35.6 MB, 24 ms. 
Mark-sweep 46.8 -> 41.1 MB, 75 ms. 
Scavenge 46.8 -> 44.0 MB, 33 ms. 
Mark-sweep 57.2 -> 50.6 MB, 92 ms. 
Scavenge 62.3 -> 56.5 MB, 26 ms. 
Scavenge 68.5 -> 62.6 MB, 24 ms. 
Scavenge 74.6 -> 68.6 MB, 26 ms. 
Mark-sweep 80.6 -> 74.5 MB, 130 ms. 
Scavenge 80.5 -> 77.6 MB, 25 ms. 
Mark-sweep 77.6 -> 77.4 MB, 112 ms. 
Mark-compact 77.4 -> 77.4 MB, 260 ms. 

即使請求停止並且GC有時間來反覆運行,內存使用量也不會減少。

我或多或少相信我必須在某處分配一個全局變量,但我無法弄清楚如何解決它。該項目的代碼住在這裏:

https://github.com/erskingardner/Readable

沒有人有我應該做的任何建議(推理)?

+4

0.3.1不穩定,0.4.0已經發布。你嘗試過嗎? – 2011-02-16 10:29:51

回答

2

我會在這裏回答我自己的問題,希望它可以幫助其他人有同樣的問題。

問題實際上是與我在創建服務器時使用的event.emitter相關。當只使用一個連接時,沒有內存泄漏(認爲是開發),但是當應用程序開始碰撞時,很多內存開始爬升爬升,GC沒有做任何事情。我在鏈中放置了一個事件監聽器,因此我創建了一個從未被銷燬的事件監聽器。

==

斷碼

Readable.prototype.createHTTPServer = function() { 
    var self = this; 

    var server = http.createServer(function(request, response) { 
    request.addListener('end', function() { 
     var location = url.parse(request.url, true) 
      ,params = (location.query || request.headers) 
      ,body  = ""; 

     if (location.pathname == '/' && request.method == "GET"){ 
     if (params["url"] == null){ 
      response.writeHead(200, { 
      'Content-Type': 'text/html' 
      }); 
      response.end("Good to go, you might want to try adding a url param though."); 
     } 
     else if (params["url"] != null){ 
      self.fetchAndParse(params["url"], params); 
     } 
     var listener = emitter.on("readability", function(result) { 
      response.writeHead(200, { 
      'Content-Type': 'text/html' 
      }); 
      if (result == "error"){ 
      response.end("error"); 
      } else { 
      response.end(result.content);   
      } 
     }); 
     } 
    }); 
    }); 
    return server 
}; 

聽者變量可能永遠不會被破壞的部分。我試圖強制刪除這個變量,但是這個響應從來沒有讓它進入瀏覽器。答案是,我所要做的就是將該監聽器var移動到else if聲明中,並在函數完成運行時自動進行GC調用。

==

正確的代碼

Readable.prototype.createHTTPServer = function() { 
    var self = this; 

    var server = http.createServer(function(request, response) { 
    request.addListener('end', function() { 
     var location = url.parse(request.url, true) 
      ,params = (location.query || request.headers) 
      ,body  = ""; 

     if (location.pathname == '/' && request.method == "GET"){ 
     if (params["url"] == null){ 
      response.writeHead(200, { 
      'Content-Type': 'text/html' 
      }); 
      response.end("Good to go, you might want to try adding a url param though."); 
     } 
     else if (params["url"] != null){ 
      self.fetchAndParse(params["url"], params); 
      var listener = emitter.on("readability", function(result) { 
      response.writeHead(200, { 
       'Content-Type': 'text/html' 
      }); 
      if (result == "error"){ 
       response.end("error"); 
      } else { 
       response.end(result.content);   
      } 
      }); 
     } 
     } 
    }); 
    }); 
    return server 
}; 
0

像PartlyCloudy提到你應該真的將你的node.js實例更新到最新最好的v0.4.0。希望bug已經修復,否則你可以在github上提交issue

我不認爲Ryan會修復那些舊的不穩定版本的錯誤。