Как я могу расшифровать значение данных памяти в node.js и отладить утечку памяти? - PullRequest
7 голосов
/ 30 мая 2011

У меня есть считыватель / скребок 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);

1 Ответ

8 голосов
/ 30 мая 2011

После прочтения этого кода я вижу, что items в GotRSSObject объявлен как глобальный, потому что нет var его префиксирования.

Кроме этого, я не вижу другой очевидной памятиутечки.Хорошим базовым методом является добавление еще нескольких операторов печати, чтобы увидеть, где выделяется память, а затем проверить, где можно ожидать очистки этой памяти, утверждая, что переменные == null.

Проблемас памятью с помощью node.js и v8 то, что сборка мусора в любой момент не гарантирована, и, на самом деле, вы не можете заставить сборку мусора происходить.Вы захотите ограничить объем данных, с которыми вы работаете, чтобы они легко помещались в памяти и обеспечили некоторую обработку ошибок (возможно, с помощью setTimeout или process.nextTick), чтобы дождаться очистки памяти.

AСлово совета с nextTick - это очень, очень быстрый звонок.Как известно, Node.js является однопоточным в цикле событий.Использование nextTick буквально выполнит эту функцию в следующем цикле - убедитесь, что вы не вызываете ее очень часто, иначе вы будете тратить время впустую.

А что касается rss, vsize, heapTotal, heapUsed ... vsize - это весь объем памяти, используемый вашим процессом, а rss - это объем физической памяти, а не подкачки.heaptotal и heapUsed относятся к базовому хранилищу v8, которое вы не можете контролировать.В основном вас интересует vsize, но вы также можете получить более подробную информацию с помощью top или Activity Monitor в OS X (кто-нибудь знает о хороших инструментах визуализации процессов в * nix системах?).

...