【问题标题】:How can I decode the meaning of memory data in node.js & debug the memory leak?如何解码 node.js 中内存数据的含义并调试内存泄漏?
【发布时间】:2011-09-04 10:31:35
【问题描述】:

我有一个 RSS 到 MongoDB 阅读器/抓取器,它运行的数据集比我的系统内存要大。当我遍历数据时,系统变慢了。我有理由确定这是因为我的内存不足。

我添加了一些调试信息并进行了一些更改,但我不知道如何阅读调试输出中给出的信息。

这是一个调试输出示例(在它变得致命之前):

 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?

另外,如果它有帮助并且为了更好地说明,我已经包含了一个代码示例。我已经做出的一项更改是将所有 require 语句移到 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);

【问题讨论】:

    标签: memory-leaks node.js memory-management


    【解决方案1】:

    阅读完这段代码后,我确实看到 GotRSSObject 中的 items 被声明为全局,因为它没有 var 前缀。

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

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

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

    关于rssvsizeheapTotalheapUsed...vsize 是您的进程正在使用的整个内存大小,rss 是实际物理内存的多少RAM而不是交换。 heaptotalheapUsed 指的是您无法控制的 v8 底层存储。您将主要关注vsize,但您也可以使用top 或OS X 上的活动监视器获得更详细的信息(有人知道*nix 系统上的良好流程可视化工具吗?)。

    【讨论】:

    • 谢谢。下一个滴答似乎真的使处理变得平滑了。知道内存值(rss、vsize、heaptotal、heapused)是什么意思吗? nodejs.org/docs/v0.4.8/api/all.html#process.memoryUsage 这里的文档不详述。
    • 对 nextTick 的忠告 - 这是一个非常非常快的调用。众所周知,Node.js 在事件循环上是单线程的。使用 nextTick 将在下一个循环中真正执行该函数 - 确保您不要经常调用它,否则您会发现自己在浪费循环。
    • 关于 rss、vsize、heaptotal、heapused...vsize 是您的进程正在使用的内存的整个大小,而 rss 是实际物理 RAM 中的多少而不是交换。 Teaptotal 和 heapused 是指您无法控制的 v8 底层存储。
    • 太棒了!谢谢 - 理想情况下,我想尽我所能使 RSS 尽可能接近 VSIZE。
    • 这可能没有实际意义。启动节点并执行 process.memoryUsage();每隔几秒钟,您就会发现各种数字不断增长。
    猜你喜欢
    • 2010-12-01
    • 2012-03-11
    • 2016-01-01
    • 1970-01-01
    • 2021-01-10
    • 2010-11-23
    • 2018-11-22
    相关资源
    最近更新 更多