2011-05-29 33 views
7

我有一个RSS到MongoDB阅读器/刮板​​,它运行的数据集大于我的系统内存。当我循环数据时,系统变慢。我相当确定这是因为我内存不足。如何在node.js中解码内存数据的含义并调试内存泄漏?

我已经添加了一些调试信息并做了一些更改,但我不知道如何读取调试输出中给出的信息。

这里有一个调试输出采样(从中获取致命前):

100 items 
Memory: { rss: 11104256,  // what is RSS? 
      vsize: 57507840,  // what is VSIZE? 
      heapTotal: 4732352, // heapTotal? 
      heapUsed: 3407624 } // heapUsed? 
200 items 
Memory: { rss: 12533760, 
      vsize: 57880576, 
      heapTotal: 6136320, 
      heapUsed: 3541984 } 
           // what key numbers do I watch for? 
           // when do I reach 'situation critical'? 
           // how do I free up memory to prevent problems? 

另外,如果有帮助,并为了更好地说明,我已经包括了代码示例。我已经做出的一个改变是将所有的需求语句移到GrabRss函数之外。

var http = require('http'); 
var sys  = require('sys'); 
var xml2js = require('xml2js'); 
var util = require('util'); 
var Db  = require('../lib/mongodb').Db, 
    Conn = require('../lib/mongodb').Connection, 
    Server = require('../lib/mongodb').Server, 
    // BSON = require('../lib/mongodb').BSONPure; 
    BSON = require('../lib/mongodb').BSONNative; 

GrabRss = function(grab, start) {   
    var options = { 
     host: 'www.example.com', 
     port: 80, 
     path: '/rss/'+grab+'/'+start 
    }; 

    var data; 
    var items; 
    var checked = 0; 
    var len = 0; 

    GotResponse = function(res) { 
     var ResponseBody = ""; 
     res.on('data', DoChunk); 
     res.on('end', EndResponse); 

     function DoChunk(chunk){ 
      ResponseBody += chunk; 
     } 
     function EndResponse() { 
      //console.log(ResponseBody); 
      var parser = new xml2js.Parser(); 
      parser.addListener('end', GotRSSObject); 
      parser.parseString(ResponseBody); 
     } 
    } 

    GotError = function(e) { 
     console.log("Got error: " + e.message); 
    } 

    GotRSSObject = function(r){ 
     items = r.item; 
     //console.log(sys.inspect(r)); 

     var db = new Db('rss', new Server('localhost', 27017, {}), {native_parser:false}); 
     db.open(function(err, db){ 
      db.collection('items', function(err, col) { 
       len = items.length; 
       if (len === 0) { 
        process.exit(0); 
       } 
       for (i in items) { 
        SaveItem(item[i], col); 
       } 
      }); 
     }); 
    } 

    SaveMovie = function(i, c) { 
     c.update({'id': i.id}, {$set: i}, {upsert: true, safe: true}, function(err){ 
      if (err) console.warn(err.message); 
      if (++checked >= len) { 
       if (checked < 5000) { 
         delete data; // added since asking 
         delete items; // added since asking 

        console.log(start+checked); 
        console.log('Memory: '+util.inspect(process.memoryUsage())); 
        GrabRss(50, start+checked); 
       } else { 
        console.log(len); 
        process.exit(0); 
       } 
      } else if (checked % 10 == 0) { 
       console.log(start+checked); 
      } 
     }); 
    } 
    http.get(options, GotResponse).on('error', GotError); 

} 
GrabRss(50, 0); 

回答

8

通过这个代码看完后,我看到items在GotRSSObject被声明为一个全球性的,因为没有var它作序。

除此之外,我没有看到其他明显的内存泄漏。一个好的基本技巧是添加更多的打印语句来查看内存分配的位置,然后通过声明变量== null来检查您希望清理内存的位置。

与node.js和v8的内存问题是,它不能保证在任何时间和垃圾收集垃圾,你不能强制垃圾收集发生。您需要限制您正在使用的数据量,以便轻松适应内存,并提供一些错误处理(可能使用setTimeout或process.nextTick)以等待内存清理完毕。

nextTick的建议 - 这是一个非常非常快的通话。众所周知,Node.js在事件循环上是单线程的。使用nextTick将在下一个循环中逐字执行该函数 - 确保不经常调用它,否则您会发现自己正在浪费周期。

和关于rssvsizeheapTotalheapUsed ... vsize是的,你的进程正在使用和rss是多少那是在实际的物理内存,而不是交换内存的整体尺寸。 heaptotalheapUsed指的是您无法控制的v8底层存储。你主要关心vsize,但你也可以通过top或OS X上的活动监视器(任何人都知道* nix系统上的良好过程可视化工具?)获得更详细的信息。

+0

谢谢。下一个勾号似乎真的已经平滑了处理。任何想法记忆值(rss,vsize,heaptotal,heapused)是什么意思?这里的文档http://nodejs.org/docs/v0.4.8/api/all.html#process.memoryUsage没有详细介绍。 – 2011-05-30 00:27:09

+0

nextTick的建议 - 这是一个非常非常快的电话。众所周知,Node.js在事件循环上是单线程的。使用nextTick将在下一个循环中逐字执行该函数 - 确保不经常调用它,否则您会发现自己正在浪费周期。 – tjarratt 2011-05-30 00:41:30

+0

关于rss,vsize,heaptotal,heapused ... vsize是您的进程正在使用的内存的整个大小,rss是实际物理内存中的多少内存,而不是交换。 Teaptotal和heapused是指您无法控制的v8底层存储。 – tjarratt 2011-05-30 00:45:18