300

我收到以下警告:

(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);

如何解决这个问题?

4

21 回答 21

291

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

我找到了这个页面,因为我收到了这个警告,在我的情况下,我正在使用的一些代码中有一个错误,它将全局对象变成了 EventEmitter!我当然建议不要在全球范围内增加限制,因为您不希望这些事情被忽视。

于 2015-07-16T00:18:18.040 回答
112

这在节点 eventEmitter 文档中进行了解释

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

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

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

于 2012-03-19T10:30:23.990 回答
104

接受的答案提供了有关如何增加限制的语义,但正如@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 之前在代码中搜索类似问题(在其他答案中进行了解释)

于 2017-06-08T23:03:21.330 回答
85

默认情况下,任何单个事件最多可以注册 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
于 2014-10-03T10:01:02.243 回答
40

替换.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 头。

于 2013-12-17T00:40:28.383 回答
8

节点版本: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 清除它。

于 2019-05-04T13:52:45.823 回答
4

在我的 mac osx 上安装 aglio 时,我也收到此警告。

我使用 cmd 修复它。

sudo npm install -g npm@next

https://github.com/npm/npm/issues/13806

于 2016-09-28T01:46:02.317 回答
2

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

于 2016-11-22T02:28:29.610 回答
2

有时这些警告发生在我们没有做的事情,而是我们忘记做的事情时!

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

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

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

于 2017-01-21T18:59:10.347 回答
2

我更喜欢寻找并解决问题,而不是尽可能地隐藏日志。在我的应用程序中观察了这个问题几天后,我意识到我req.socket在 Express 中间件中设置了侦听器,以捕获不断弹出的套接字 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();
    }

删除该中间件会停止您看到的警告。我会环顾您的代码并尝试找到您可能设置不需要的侦听器的任何地方。

于 2018-05-13T01:53:27.233 回答
1

感谢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')监听器,瞧……解决了!希望这对您有所帮助。

于 2020-03-03T04:10:23.477 回答
1

我遇到了同样的问题。问题是因为我在 2 个侦听器上侦听端口 8080。

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

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

于 2018-01-24T12:27:49.250 回答
1

直到今天我开始的时候我一直在吃这个grunt watch。终于解决了

watch: {
  options: {
    maxListeners: 99,
    livereload: true
  },
}

烦人的消息消失了。

于 2017-05-11T06:51:25.857 回答
1

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

客户端服务器

socket.removeAllListeners(); 

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

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

this.socket.removeAllListeners("connect");
于 2018-12-30T10:44:41.637 回答
1

正如其他人指出的那样,增加限制并不是最好的答案。我遇到了同样的问题,但在我的代码中,我没有使用任何事件监听器。当我仔细查看代码时,我有时会创建很多 Promise。每个 Promise 都有一些抓取提供的 URL 的代码(使用一些第三方库)。如果你正在做类似的事情,那么它可能是原因。

请参阅此线程以了解如何防止这种情况:使用 ES6 的 Promise.all() 时限制并发的最佳方法是什么?

于 2021-02-02T10:38:58.770 回答
1

我遇到了同样的问题,但我已经成功处理了异步等待。
请检查它是否有帮助。

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

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

于 2020-01-28T09:07:58.840 回答
0

在我的情况下,这是由于在使用 setInterval 调用的异步函数内部创建它们时没有关闭与数据库的 Sequelize 连接。

于 2021-03-30T21:40:34.893 回答
0

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

于 2016-07-06T13:41:16.610 回答
0

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

该错误与我们应用程序的实际代码无关,而是我们的开发环境有关。

于 2017-04-20T23:40:24.253 回答
-1

添加EventEmitter.defaultMaxListeners = <MaxNumberOfClients>node_modules\loopback-datasource-juggler\lib\datasource.js固定的可能问题:)

于 2021-05-31T05:37:23.100 回答
-4

把它放在你的 server.js 的第一行(或任何包含你的主要 Node.js 应用程序):

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

并且错误消失了:)

于 2016-02-10T13:02:19.327 回答