检测到可能的EventEmitter内存泄漏


231

我收到以下警告:

(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace: 
    at EventEmitter.<anonymous> (events.js:139:15)
    at EventEmitter.<anonymous> (node.js:385:29)
    at Server.<anonymous> (server.js:20:17)
    at Server.emit (events.js:70:17)
    at HTTPParser.onIncoming (http.js:1514:12)
    at HTTPParser.onHeadersComplete (http.js:102:31)
    at Socket.ondata (http.js:1410:22)
    at TCP.onread (net.js:354:27)

我在server.js中编写了这样的代码:

http.createServer(
    function (req, res) { ... }).listen(3013);

如何解决?


46
使用process.on('warning', e => console.warn(e.stack));调试警告。不要使用process.setMaxListeners(0);警告,因为某种原因。
Shwetabh Shekhar

谢谢。非常有用的说明。
Abdullah Al Farooq

这个错误发生在我身上yarn install。我在哪里可以将此行添加堆栈跟踪?
Sonic Soul,

Answers:


94

这是在解释节点eventEmitter文档

这是哪个版本的Node?您还有什么其他代码?那不是正常的行为。

简而言之,其: process.setMaxListeners(0);

另请参见:node.js-请求-如何“ emitter.setMaxListeners()”?


1
v0.6.11 ...我已经做了一切,但警告仍然存在。:(
Riz 2012年

5
我正在使用process.on('uncaughtException', callback);
Riz 2012年

9
process.setMaxListeners(0); // OMG, its so simple... :D
黎兹2012年

11
我不会删除最大侦听器限制。您不会收到警告,但是会出现内存泄漏。

15
这个答案是如何获得所有这些投票的,并被选为正确答案?即使它可以工作,但这是完全错误的!
ProllyGeek

203

我想在此指出警告的出现是有原因的,正确的解决办法很有可能不会增加限制,而是要弄清楚为什么要在同一事件中添加如此多的侦听器。仅当您知道为什么要添加如此多的侦听器并确信这是您真正想要的时,才增加限制。

我找到此页面是因为收到此警告,并且在我的情况下,我正在使用的某些代码中存在一个错误,该错误将全局对象转换为EventEmitter!我当然不建议在全球范围内增加限制,因为您不希望这些事情被忽视。


14
+1。同意 该警告表明潜在的泄漏状态,并且不加考虑地增加maxListeners并不一定能解决问题。jongleberry.com/understanding-possible-eventemitter-leaks.html
耶利米亚当斯

3
如何调试“警告:检测到可能的EventEmitter内存泄漏。添加了11个错误侦听器。使用generator.setMaxListeners()增加限制”。我们应该寻找什么?
菲尔(Phil)

2
但是没有堆栈跟踪,并且没有任何错误代码与代码。我在“警告”和“可能”上有大写的“ W”和“ P”,所以我认为这可能是一个不同的错误。我需要侦听多个事件,但在任何情况下我都只会调用一次。因此不确定是什么问题。
菲尔

2
@ Phil_1984_您找到解决方案了吗?如果没有这似乎工作- stackoverflow.com/questions/38482223/...
号Yoni扎哈

3
仅供参考,第一个评论的链接(jongleberry.com)已离线。这是存档的版本:web.archive.org/web/20180315203155/http
杰夫·沃德

76

默认情况下,任何单个事件最多可以注册10个侦听器。

如果是您的代码,则可以通过以下方式指定maxListeners:

const emitter = new EventEmitter()
emitter.setMaxListeners(100)
// or 0 to turn off the limit
emitter.setMaxListeners(0)

但是,如果不是您的代码,则可以使用技巧来全局增加默认限制:

require('events').EventEmitter.prototype._maxListeners = 100;

当然,您可以关闭限制,但要小心:

// turn off limits by default (BE CAREFUL)
require('events').EventEmitter.prototype._maxListeners = 0;

顺便说一句。代码应在应用程序的开头。

添加:由于节点0.11,此代码还可以更改默认限制:

require('events').EventEmitter.defaultMaxListeners = 0

5
这是在Node 5.6.0中对我有用的唯一解决方案。万分感谢!
安德鲁·福克纳

我使用的是本机节点版本8。*。*。这对我不起作用。
托马斯·瓦拉德兹

我的是require('events')。EventEmitter.defaultMaxListeners = Infinity;
卡尔·安东尼·巴卢约

72

接受的答案提供了有关如何增加限制的语义,但正如@voltrevo指出的,警告是有原因的,您的代码可能存在错误。

考虑以下错误代码:

//Assume Logger is a module that emits errors
var Logger = require('./Logger.js');

for (var i = 0; i < 11; i++) {
    //BUG: This will cause the warning
    //As the event listener is added in a loop
    Logger.on('error', function (err) {
        console.log('error writing log: ' + err)
    });

    Logger.writeLog('Hello');
}

现在观察添加侦听器的正确方法:

//Good: event listener is not in a loop
Logger.on('error', function (err) {
    console.log('error writing log: ' + err)
});

for (var i = 0; i < 11; i++) {
    Logger.writeLog('Hello');
}

更改maxListeners之前,请在代码中搜索类似的问题(其他答案对此进行了解释)


13
该答案应该被接受,因为它显示了警告背后的实际原因以及解决方法,+ 1
Ganesh Karewad

这是正确的答案!老实说,我认为出现maxListener警告主要是由于某些错误代码。就我而言,这是mysql代码。我将尝试给出一个答案,只是为了使其更加清晰。
阿德里安

25

更换 .on()once()once()当事件由同一函数处理时,使用会删除事件侦听器。

如果这不能解决问题,请在package.json“ restler”中重新安装restler:“ git://github.com/danwrong/restler.git#9d455ff14c57ddbe263dbbcd0289d76413bfe07d”

这与restler 0.10与节点的行为异常有关。您可以在以下位置查看git上已关闭的问题:https : //github.com/danwrong/restler/issues/112 但是,npm尚未更新它,因此这就是为什么您必须引用git head的原因。


这使用Puppeterr框架在我的代码上解决了此错误
C Alonso C Ortega


4

节点版本:v11.10.1

来自堆栈跟踪的警告消息:

process.on('warning', e => console.warn(e.stack));
(node:17905) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 wakeup listeners added. Use emitter.setMaxListeners() to increase limit
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 wakeup listeners added. Use emitter.setMaxListeners() to increase limit
    at _addListener (events.js:255:17)
    at Connection.addListener (events.js:271:10)
    at Connection.Readable.on (_stream_readable.js:826:35)
    at Connection.once (events.js:300:8)
    at Connection._send (/var/www/html/fleet-node-api/node_modules/http2/lib/protocol/connection.js:355:10)
    at processImmediate (timers.js:637:19)
    at process.topLevelDomainCallback (domain.js:126:23)

搜索github问题,文档并创建类似的事件发射器内存泄漏后,由于用于iOS推送通知的node-apn模块,发现了此问题。

这解决了它:

您应该为每个拥有的证书/密钥对只为每个进程创建一个提供者。您无需为每个通知创建一个新的提供程序。如果您仅将通知发送到一个应用程序,则不需要多个提供商。

如果您在应用程序中不断创建Provider实例,请确保在完成每个提供者的操作后调用Provider.shutdown()以释放其资源和内存。

每次发送通知时,我都在创建提供程序对象,并期望gc清除它。


2

就我而言,child.stderr.pipe(process.stderr)当我启动该孩子的10个(或大约)实例时,它就是被调用的。因此,导致将事件处理程序附加到LOOP中的同一EventEmitter对象的任何事情,都会导致nodejs抛出此错误。


2

有时,当这些警告不是我们已经完成但我们忘记要做的事情时,就会发生!

我在使用npm安装dotenv软件包时遇到了此警告,但是在我开始在应用程序的开头添加require('dotenv')。load()语句之前被中断。回到项目后,我开始收到“检测到可能的EventEmitter内存泄漏”警告。

我认为问题出在我做过的事情上,而不是我没有做过的事情!

一旦发现疏忽并添加了require语句,便清除了内存泄漏警告。


2

我更喜欢寻找和解决问题,而不是尽可能地抑制日志。在几天后在我的应用程序中观察到此问题后,我意识到我正在req.socketExpress中间件中的上设置侦听器,以捕获不断弹出的套接字io错误。在某个时候,我了解到这不是必须的,但是无论如何我都会让听众保持联系。我只是删除了它们,而您遇到的错误就消失了。我通过运行带有和不带有以下中间件的服务器请求来验证这是原因:

socketEventsHandler(req, res, next) {
        req.socket.on("error", function(err) {
            console.error('------REQ ERROR')
            console.error(err.stack)
        });
        res.socket.on("error", function(err) {
            console.error('------RES ERROR')
            console.error(err.stack)
        });
        next();
    }

删除该中间件将停止您所看到的警告。我会四处查看您的代码,并尝试查找可能在其中设置不需要的侦听器的任何地方。


1

我有同样的问题。和问题是由于我在2个侦听器上监听端口8080而引起的。

setMaxListeners() 工作正常,但我不推荐它。

正确的方法是检查您的代码中是否有其他侦听器,删除侦听器或更改您正在侦听的端口号,这解决了我的问题。



1

在使用以下方法创建新的侦听器之前,需要清除所有侦听器:

客户端服务器

socket.removeAllListeners(); 

假设套接字是您的客户端套接字/或创建的服务器套接字。

您还可以订阅特定的事件侦听器,例如connect像这样删除侦听器:

this.socket.removeAllListeners("connect");

0

您说您正在使用process.on('uncaughtException', callback);
在哪里执行此语句?是在传递给的回调中http.createServer吗?
如果是,则在每个新请求时,同一回调的不同副本将附加到uncaughtException事件,因为function (req, res) { ... }每次新请求进入时都会执行该获取,因此语句也将process.on('uncaughtException', callback);
注意该过程对象是所有请求和添加侦听器的全局对象每次收到新请求都毫无意义。您可能不想要这种行为。
如果要为每个新请求附加一个新的侦听器,则应删除附加到该事件的所有以前的侦听器,因为不再需要使用以下方法:
process.removeAllListeners('uncaughtException');


0

我们团队对此的解决方法是从.npmrc中删除注册表路径。我们在rc文件中有两个路径别名,一个是指向已被弃用的Artifactory实例。

错误无关,与我们的应用程序的实际代码,但一切都与我们的开发环境。


0

我面临着同样的问题,但是我已经成功地通过异步等待进行了处理。
请检查是否有帮助。

让dataLength = 25;
之前:
  for(让i = 0; i <dataLength; i ++){
      sftp.get(remotePath,fs.createWriteStream(xyzProject/${data[i].name}));
  }

之后:
  for(let i = 0; i <dataLength; i ++){
      等待sftp.get(remotePath,fs.createWriteStream(xyzProject/${data[i].name}));
  }


0

感谢RLaaa为我提供了一个解决实际问题/警告根本原因的想法。好吧,在我看来,这是MySQL错误代码。

为您提供一个Promise,其中包含如下代码:

pool.getConnection((err, conn) => {

  if(err) reject(err)

  const q = 'SELECT * from `a_table`'

  conn.query(q, [], (err, rows) => {

    conn.release()

    if(err) reject(err)

    // do something
  })

  conn.on('error', (err) => {

     reject(err)
  })
})

请注意conn.on('error'),代码中有一个侦听器。从字面上看,该代码一遍又一遍地添加侦听器取决于您调用查询的次数。同时if(err) reject(err)做同样的事情。

所以我删除了conn.on('error')听众,瞧……解决了!希望这对您有所帮助。


-4

将其放在server.js(或包含主Node.js应用的任何内容)的第一行中:

require('events').EventEmitter.prototype._maxListeners = 0;

错误消失了:)


您给了我一个将其放入主文件的想法,并且它起作用了。我只是把它放在错误的地方。谢谢!
sklimkovitch
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.