为什么这个NodeJS代码会泄漏内存?

时间:2017-03-02 00:15:14

标签: node.js memory memory-leaks

我有一个使用模块stats的NodeJS应用程序。 stats模块旨在跟踪基本上只是速率:每秒请求数等等。在我尝试将此代码投入生产之前,这一切看起来都相当简单。在部署环境中,此代码泄漏,并且非常糟糕。删除此代码并且泄漏消失。我很困惑为什么会发生这种情况,因为没有明显的内存泄漏给我。请记住,我是一个不错的新手,所以这里可能会有一些细微差别,因为我与内存分配和回收有关。

这是统计模块:

// stats.js
const meters = {};


class ExponentiallyWeightedMovingAverage {
  constructor(timePeriod = 1000 * 60, tickInterval = 1000 * 5) {
    this.timePeriod = timePeriod;
    this.tickInterval = tickInterval;

    this.alpha = 1 - Math.exp(-this.tickInterval / this.timePeriod);
    this.count = 0;
    this.rate = 0;

    this.update = this.update.bind(this);
    this.tick = this.tick.bind(this);
  }

  update(n) {
    this.count += n;
  }

  tick() {
    const instantRate = this.count / this.tickInterval;
    this.count = 0;

    this.rate += (this.alpha * (instantRate - this.rate));
  }

  getRate(timeUnit) {
    return this.rate * timeUnit;
  }
}


function meter(name) {
  if (name in meters) {
    return meters[name];
  }

  const rateUnit = 1000;
  const tickInterval = 5 * 1000;

  const m1Rate = new ExponentiallyWeightedMovingAverage(1 * 60 * 1000, tickInterval);
  const m5Rate = new ExponentiallyWeightedMovingAverage(5 * 60 * 1000, tickInterval);
  const m15Rate = new ExponentiallyWeightedMovingAverage(15 * 60 * 1000, tickInterval);

  let count = 0;

  function mark(n = 1) {
    count += n;
    m1Rate.update(n);
    m5Rate.update(n);
    m15Rate.update(n);
  }

  function tick() {
    m1Rate.tick();
    m5Rate.tick();
    m15Rate.tick();
  }

  setInterval(tick, tickInterval);

  function meterToJSON() {
    return {
      count,
      '1MinuteRate': m1Rate.getRate(rateUnit),
      '5MinuteRate': m5Rate.getRate(rateUnit),
      '15MinuteRate': m15Rate.getRate(rateUnit),
    };
  }

  meters[name] = { mark, toJSON: meterToJSON };
  return meters[name];
}


function toJSON() {
  const objs = {};

  Object.entries(meters).forEach(([name, storedMeter]) => {
    const obj = {};
    obj[name] = storedMeter.toJSON();
    Object.assign(objs, obj);
  });

  return objs;
}


const global = { meter, toJSON };

module.exports = { global };

现在,这在我的Node应用程序中的Connect中间件中使用。基本上是这样的:

// middleware/collect-stats.js
import stats from '../stats';

...

const host = 'www.example.com';
stats.global.meter(`originLatency${host}`).mark(time);

稍后在中间件链中再次出现:

// middleware/proxy-req.js
import stats from '../stats';

...

const currentStats = stats.global.toJSON();
const latency = currentStats['originLatencywww.example.com'];
console.log(latency['1MinuteRate']);

我在这里简化了延迟实际消耗的方式,但这是所发生的事情的要点。

此代码是否有任何泄漏原因?为什么这会最大化我的EC2实例上的内存,导致它们最终崩溃?

请注意,在生产中,它通过FROM节点:7.4(即节点7.4)在Docker容器中的EC2上运行。 (7.6的泄漏情况要差得多。)

0 个答案:

没有答案