小nodejs进程正在吃113m的内存

时间:2013-07-28 22:57:46

标签: node.js memory

我正在尝试使用nodejs将外部API中的数据保存到mongodb中。脚本对我来说感觉非常轻巧,但由于某种原因,它使用了大量的RAM(来自top):

 PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND 
 2626 root      20   0  756m 113m 7148 S  6.5 11.4   3:11.74 nodejs  

这是脚本在伪代码中的作用:

each 5 seconds
  fetch 3 JSON lists through an API
    for all new items in list
      store in mongo

[编辑] JSON列表是aprox。每个10kb。因此,我不认为在处理项目之前将其保留在内存中是不可行的。 [/编辑]

(轻)依赖关系是:

  • 查询字符串
  • HTTPS
  • 下划线
  • mongodb(原生客户)

我把它写成简单的函数,返回时它们应该回放它们使用的所有内存吗?

以下是整个脚本:

var querystring = require("querystring");
var https = require('https');

var fetch = function(cur, callback) {
  cur = cur.toLowerCase().replace('/', '_');
  var options = {
    host: 'data.fxbtc.com',
    path: '/api?op=query_last_trades&count=100&symbol=' + cur,
    method: 'GET',
    headers: {
      'User-Agent': 'Mozilla/4.0 (compatible; node.js client)'
    }
  };

  var req = https.request(options, function(res) {
    res.setEncoding('utf8');
    var buffer = '';
    res.on('data', function(data) {
      buffer += data;
    });
    res.on('end', function() {
      try {
        var json = JSON.parse(buffer);
      } catch (err) {
        return callback(err);
      }
      callback(null, json);
    });
  });
  req.end();
}

var currencies = [
  'BTC/CNY',
  'LTC/CNY',
  'LTC/BTC'
];

var LAST_TRADE = {
  'BTC/CNY': 0,
  'LTC/CNY': 0,
  'LTC/BTC': 0
}

var _ = require('underscore');
var mongo = require('mongodb');
var moment = require('moment');

var init = function(next) {
  mongo.connect('mongodb://127.0.0.1:27017/coindata', next);
}

var now = function() {
  return moment().format('YYYY-MM-DD HH:mm:ss');
}

console.log(now(), 'STARTING');

setInterval(function() {
  console.log(now(), 'alive')
}, 60000)

var collections = {};

var forever = function(err, db) {
  if(err) throw err;

  _.each(currencies, function(cur, i) {
    collections[cur] = db.collection('fxbtc_' + cur);
    collections[cur].ensureIndex({fid: 1}, {unique: true}, console.log);

    setTimeout(function() {
      console.log(now(), 'registering', cur);
      setInterval(check(cur), 5 * 1000);
    }, i * 1000);
  });
}

var check = function(cur) {
  return function() {
    fetch(cur, function(err, trades) {
      if(err) return console.log(now(), 'ERROR-FETCH', err);

      trades = _.map(trades.datas, function(trade) {
        return {
          date: new Date(trade.date * 1000),
          price: parseFloat(trade.rate),
          amount: parseFloat(trade.vol),
          fid: parseInt(trade.ticket)
        }
      });

      trades = _.filter(trades, function(trade) {
        return trade.fid > LAST_TRADE[cur];
      });

      var fids = _.pluck(trades, 'fid');
      fids.push(LAST_TRADE[cur]);

      LAST_TRADE[cur] = _.max(fids);

      if(!trades.length)
        return;

      console.log(now(), 'storing:', trades.length, 'in', cur);

      collections[cur].insert(trades, function(err, docs) {
        if(err && err.code !== 11000) console.log(now(), 'ERROR-STORE', err);
      });

    });
  }
}


init(forever);

此脚本中是否有明显的内存泄漏?如何查找所有已用内存的来源?

1 个答案:

答案 0 :(得分:0)

我正在处理的项目是轮询许多不同的API服务(15+)并存储所有最新的更改。

我最初的想法是为每个不同的服务编写一个小脚本,里面有一个循环,应该永远保持不变。问题(如上所述)是每个服务的内存会以某种方式增长到40-120mb(取决于几件事),而我的系统会耗尽RAM。

这就是我现在解决的问题:

而不是保持每个服务的进程保持活动状态我重写了所有脚本只运​​行一次并写了一个主脚本,负责在x个时间后运行每个服务脚本的每个脚本:

var cp = require('child_process');
var moment = require('moment');

var i = 0;

var watch = function(options) {
  i++;
  setTimeout(function() {
    var fid = 0;
    setInterval(function() {
      var worker = cp.fork('./process_' + options.exchange + '.js');
      worker.send(fid);
      worker.once('message', function(new_fid) {
        fid = new_fid;
        worker.kill();
      });
    }, options.interval);  
  }, i * 3000);

}

然后我注册所有不同的服务:

watch({exchange: 'bitcurex', interval: +moment.duration(9, 'minutes')});

它已运行了10多个小时或现在几乎没有内存占用(我无法在顶部找到它)。