为什么Node.js有增量内存使用?

时间:2015-06-02 23:10:37

标签: node.js websocket

我有一个大于100 KB的gameserver.js文件。我在浏览器上每次刷新后都会一直检查我的任务管理器,并且每次刷新时我的node.exe内存使用率都会不断上升。我在这里使用ws模块:https://github.com/websockets/ws并想通了,你知道吗,我的代码中某处内存泄漏最有可能...

因此,要仔细检查并隔离问题,我创建了一个test.js文件并放入默认的ws代码块:

var WebSocketServer = require('ws').Server
  , wss = new WebSocketServer({ port: 9300 });

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    console.log('received: %s', message);
  });
});

启动它:

Enter image description here

现在,我检查node.exe的内存使用情况:

Enter image description here

令我困惑的增量部分是:

如果我刷新我的浏览器连接到此端口9300 websocket服务器,然后回顾我的任务管理器..它显示:

Enter image description here

现在位于: 14,500 K

每次刷新时它都会不断上升,所以从理论上讲,如果我保持清醒它将会通过屋顶。这是有意的吗?某个地方ws模块中是否存在内存泄漏?我问的全部原因是因为我认为可能在几分钟内或当用户关闭浏览器时它会回落,但事实并非如此。

我想要进行此测试的核心原因是因为我认为我的个人代码中存在内存泄漏问题并且只是想检查它是不是我,反之亦然。现在我很难过。

2 个答案:

答案 0 :(得分:18)

看到Node.js应用程序增加内存占用是完全正常的行为。 Node.js不断分析您运行的代码,生成优化的代码,恢复到未优化的代码(如果需要)等等。即使对于最简单的应用程序,所有这些都需要相当多的内存(Node.js本身来自大部分内容)在JavaScript中遵循与您自己的代码相同的优化/去优化。)

此外,可以在需要时为进程授予更多内存,但是许多操作系统仅在他们认为在其他地方(即通过其他进程)需要时才从进程中删除分配的内存。因此,应用程序可以在峰值中消耗1 GB的RAM,然后启动垃圾回收,使用率降至500 MB,但该过程仍可保持1 GB。

检测是否存在内存泄漏

要正确分析内存使用情况和内存泄漏,必须使用Node.js process.memoryUsage()

你应该设置一个间隔,将这个内存使用量转储到一个文件中,即每秒,然后应用一些"压力"在你的应用程序上几秒钟(即对于Web服务器,发出几千个请求)。然后看看结果,看看内存是否继续增加,或者它是否遵循稳定的增加/减少模式。

检测内存泄漏源

最好的工具可能是node-heapdump。您可以将它与Chrome调试器一起使用。

  1. 启动您的应用程序并应用初始压力(这是为了生成优化的代码和#34;预热"您的应用程序)
  2. 当应用程序处于空闲状态时,生成一个heapdump
  3. 执行您怀疑可能会导致内存泄漏的单个附加操作(即一个请求) - 这可能是最棘手的部分,特别是对于大型应用程序
  4. 生成另一个heapdump
  5. 将两个heapdump加载到Chrome调试器中并进行比较 - 如果存在内存泄漏,您将看到在该单个请求期间分配了一些对象但之后未发布的对象
  6. 检查对象以确定泄漏发生的位置
  7. 我有机会调查Sails.js框架中报告的内存泄漏 - 您可以在this issue上看到详细的分析描述(包括漂亮的图形等)。

    StrongLoop还有一个关于使用heapdumps的detailed article - 我建议看看它。

答案 1 :(得分:6)

垃圾收集器不会一直调用,因为它会阻止您的进程。因此,V8在认为必要时启动GC。

要查找是否有内存泄漏我建议在每次请求后手动启动GC,看看你的内存是否仍在上升。通常,如果你没有内存泄漏,你的记忆力不应该增加。因为GC将清除所有未使用的对象。如果在GC调用后内存仍在上升,则会导致内存泄漏。

要手动启动GC,您可以这样做,但请注意!不要在生产中使用它;这只是一种清理内存并查看是否有内存泄漏的方法。

像这样启动Node.js:

node --expose-gc --always-compact test.js

它将暴露垃圾收集器并强制它具有攻击性。调用此方法运行GC:

global.gc();

在每次点击服务器后调用此方法,看看GC是否清理内存。

您还可以在请求之前和之后执行两个进程堆转换,以查看差异。

请勿在生产或项目中使用此功能。这只是一种查看是否有内存泄漏的方法。