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

我有一个超过100 KB的gameserver.js文件。 每次刷新浏览器后,我都会继续检查我的任务pipe理器,并且每次刷新都会继续看到我的node.exe内存使用率持续上升。 我在这里使用ws模块: https : //github.com/websockets/ws ,想通了,你知道吗, 我的代码中有很多内存泄漏。

所以要仔细检查和隔离问题,我创build了一个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); }); }); 

并启动它:

在这里输入图像说明

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

在这里输入图像说明

让我困惑的增量部分是:

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

在这里输入图像说明

现在是: 14,500 K

每刷新一次,它就会不断上升,所以理论上如果我保持清醒的话就会经过屋顶。 这是打算? 是否有可能在ws模块内存泄漏? 我所要求的全部原因是因为我想也许在几分钟内或者当用户closures浏览器时,它将会回落,但是不会。

而我想做这个testing的核心原因是因为我想我在个人代码的某个地方有一个内存泄漏问题,只是想检查它是不是我,反之亦然。 现在我很难过

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

另外,一个进程在需要的时候可以被授予更多的内存,但是许多操作系统只有在他们决定在其他地方(即通过另一个进程)需要的时候才从进程中移除分配的内存。 因此,应用程序可以在峰值时消耗1 GB的RAM,然后垃圾回收开始,使用率下降到500 MB,但是进程可能仍然保持1 GB。

检测是否存在内存泄漏

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

你应该设置一个时间间隔,把这个内存使用量转换成一个文件,也就是每秒钟,然后在几秒钟内对应用程序施加一些“压力”(例如,对于Web服务器,发出几千个请求)。 然后看看结果,看看记忆力是否持续增长,或者是否持续增长/减less。

检测内存泄漏的来源

最好的工具是node-heapdump 。 您可以在Chromedebugging器中使用它。

  1. 启动您的应用程序并施加初始压力(这是为了生成优化的代码并“预热”您的应用程序)
  2. 应用程序闲置时,生成一个堆转储
  3. 执行一个额外的操作(即多一个请求),您怀疑可能会导致内存泄漏 – 这可能是最棘手的部分,特别是对于大型应用程序
  4. 生成另一个heapdump
  5. 加载堆转储到Chromedebugging器,并比较它们 – 如果有内存泄漏,你会看到有一些对象,在这个单一的请求分配,但没有释放之后
  6. 检查物体以确定发生泄漏的位置

我有机会在Sails.js框架中调查报告的内存泄漏 – 你可以在这个问题上看到详细的分析描述(包括漂亮的graphics等)。

还有一篇关于使用StrongLoop进行堆转储的详细文章 – 我build议查看一下。

垃圾收集器不会一直被调用,因为它阻塞了你的进程。 所以V8在认为有必要的时候启动GC。

为了查找是否有内存泄漏,我build议在每次请求后手动启动GC,以查看内存是否仍在上升。 通常情况下,如果你没有内存泄漏,你的内存不应该增加。 因为GC将清理所有未使用的对象。 如果在GC调用之后你的内存仍然在增加,那么你的内存泄漏了。

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

像这样启动Node.js:

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

它会暴露垃圾收集器,并强制它是积极的。 调用这个方法来运行GC:

 global.gc(); 

在你的服务器每次命中后调用这个方法,看看GC是否清理内存。

你也可以在请求之前和之后做两个堆进程,看看有什么不同。

不要在生产或项目中使用它。 这只是看你是否有内存泄漏的方法。