检测到可能的EventEmitter内存泄漏

我得到以下警告:

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

如何解决这个问题?

475621 次浏览

这在节点eventEmitter文档中解释

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

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

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

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

如果这不能解决它,然后在你的package.json中重新安装这个restler :“restler git: / / github.com/danwrong/restler.git # 9 d455ff14c57ddbe263dbbcd0289d76413bfe07d”< / p >

这与restler 0.10对node的错误行为有关。你可以在这里看到git关闭的问题:https://github.com/danwrong/restler/issues/112 然而,npm还没有更新这个,所以这就是为什么你必须引用git头

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

如果这是你的代码,你可以通过:

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;

顺便说一句。代码应该在应用程序的最开始。

ADD:从节点0.11开始,这段代码也可以改变默认限制:

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

我想在这里指出,这个警告是有原因的,而且很有可能正确的修复是增加限制,但要弄清楚为什么你向同一个事件添加了这么多监听器。只有当您知道为什么要添加这么多侦听器并且确信这是您真正想要的时候,才增加限制。

我找到了这个页面,因为我得到了这个警告,在我的情况下,我正在使用的一些代码中有一个错误,将全局对象转换为EventEmitter!我当然不建议在全球范围内增加限制,因为你不想让这些事情被忽视。

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

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

错误就消失了:)

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

当我在mac osx上安装aglio时,我也得到了这个警告。

我使用cmd修复它。

sudo npm install -g npm@next

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

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

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

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

我以为问题出在我做了什么,而不是我没做什么!

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

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

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

我有这个直到今天,当我开始grunt watch。最终由

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

烦人的信息消失了。

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

考虑以下有bug的代码:

//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之前搜索代码中的类似问题(在其他答案中有解释)

我也有同样的问题。这个问题是因为我在两个监听器上监听端口8080。

setMaxListeners()工作很好,但我不推荐它。

正确的方法是,检查你的代码额外的监听器,删除监听器或改变端口号,你正在监听,这解决了我的问题。

我更喜欢在任何可能的情况下查找和修复问题,而不是压制日志。在我的应用程序中观察了几天这个问题后,我意识到我在一个Express中间件中的req.socket上设置了侦听器,以捕捉不断弹出的socket 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();
}

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

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

客户端/服务器

socket.removeAllListeners();

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

你也可以订阅特定的事件监听器,比如像这样删除connect监听器:

this.socket.removeAllListeners("connect");

节点版本号: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问题,文档和创建类似的事件发射器内存泄漏后,由于node-apn模块用于iOS推送通知而观察到此问题。

这就解决了问题:

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

如果你经常在你的应用程序中创建Provider实例,make 当你使用完每个提供者时,一定要调用provider .shutdown()

.释放资源和内存

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

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

let dataLength = 25;
之前:
for (let I = 0;我& lt;dataLength;i++) {
,,,, sftp。
. get(remotePath, fs.createWriteStream(xyzProject/${data[i].name}))

后:
for (let I = 0;我& lt;dataLength;i++) {
,,,,,等待sftp。
. get(remotePath, fs.createWriteStream(xyzProject/${data[i].name})) ,,} < / p >

感谢RLaaa给了我一个如何解决警告的真正问题/根本原因的想法。在我的例子中,是MySQL有bug的代码。

假设你写了一个承诺,里面的代码是这样的:

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')监听器,瞧…解决了!

.

.

正如其他人所指出的那样,提高限额并不是最好的答案。我也面临着同样的问题,但在我的代码中,我没有使用任何事件侦听器。当我仔细研究代码时,我有时会创建很多承诺。每个承诺都有一些抓取所提供URL的代码(使用一些第三方库)。如果你正在做类似的事情,那么它可能是原因。

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

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

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