在节点js中永远不会释放使用的内存。很奇怪

时间:2014-11-26 14:04:51

标签: node.js memory-leaks

我刚刚完成开发我的第一个node.js应用程序,现在我正在我的VPS上测试它。观察过程资源的使用情况"节点",我注意到当请求页面(特别是某些页面)时内存使用量增加。特别是,如果请求的页面是静态页面,则增加量最小。如果请求的页面是/ admin,则增加可以是1mb!当然,当请求/ admin时,我的服务器做的事情比提供静态页面要多。他连接到mongodb,执行4"找到",他使用bind将结果绑定到html模板。现在,问题是什么?使用这个内存,永远不会释放!所以我认为我的代码中存在逻辑错误,但后来我做了另一个更有趣的测试。

考虑这个非常简单的nodejs服务器:

 var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(3000, 'my_public_ip');

如果我尝试使用浏览器发出多个请求(只需按住f5一分钟),内存使用量就会缓慢增长,并且即使经过很长时间和关闭浏览器之后,进程使用的内存也永远不会被释放。现在,很可能在我的/管理员代码中存在一些错误(使用的内存为1mb,并且每次请求都没有释放它非常高!),但我认为这很奇怪以上简单脚本使用的内存永远不会被释放!你怎么看待这件事?有办法避免吗?

另外,(在我的真实服务器中),我使用了memwatch

    var memwatch = require('memwatch');
    memwatch.on('leak', function(info) {
       console.log(info); 
       process.exit(1);
    });

如果我使用浏览器执行多个请求,在我执行此操作大约10秒后,该过程将退出,这是错误:

{ start: Wed Nov 26 2014 08:21:07 GMT-0500 (EST),
  end: Wed Nov 26 2014 08:22:04 GMT-0500 (EST),
  growth: 4775624,
  reason: 'heap growth over 5 consecutive GCs (57s) - 287.65 mb/hr' }

这是什么意思?好像与垃圾收集器有关!我知道在这里粘贴我的/管理员代码会更好但是片段很长并且与全局变量有关,所以如果没有200行副本就不可能理解:D。如果您需要更多信息,我会给你!

1 个答案:

答案 0 :(得分:5)

节点不释放内存并不奇怪,大多数程序都没有。他们很贪婪:如果他们做得不够,他们会从系统中获得更多的记忆。如果他们有额外的,他们会保留它以供以后使用。

短样本服务器没有泄漏内存。我用节点v0.10.29进行了14分钟的测试;内存使用最初只是缓慢增长,然后停止。每个http调用的增长率小于一位,因此它不能在调用本身中泄漏内存。有可能由nodejs运行时引起的内存碎片可能导致堆增长,直到有足够的备用内存来弥补碎片。

14分钟后,nodejs进程仍然只使用其21MB堆中的2MB,就像它启动时一样。 (14因为15分钟的比赛暂停了1:09)

这是超过246万次http调用的增长(仅显示heapTotal更改和final。最终内存占用时间在4分钟后达到,并且在接下来的11分钟内不会更改):

2014-12-03T04:52:48.358Z {rss:12222464,heapTotal:7130752,heapUsed:1751228}
2014-12-03T04:52:55.182Z {rss:17326080,heapTotal:9227904,heapUsed:2186528}

2014-12-03T04:53:59.488Z {rss:21172224,heapTotal:13422208,heapUsed:2092796}
2014-12-03T04:56:58.897Z {rss:29556736,heapTotal:21810816,heapUsed:2100000}

(...在05:02:27左右以1:09暂停) 2014-12-03T05:07:45.598Z {rss:29446144,heapTotal:21810816,heapUsed:2138608}

我的(稍加修改)测试:

var ncalls = 0;
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
  if (ncalls++ % 100000 === 0) {
    global.gc();
    console.log(new Date().toISOString(), process.memoryUsage());
  }
}).listen(3000, '127.0.0.1');
console.log("Listening on 3000...");