javascript MaxListenersExceededWarning:检测到可能的 EventEmitter 内存泄漏。添加了 11 个消息列表。使用emitter.setMaxListeners() 增加限制
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/50709059/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 message lis teners added. Use emitter.setMaxListeners() to increase limit
提问by Nane
I know this might flag as a duplicate solution but solution on stack overflow is not working for me.
我知道这可能会标记为重复的解决方案,但堆栈溢出的解决方案对我不起作用。
Problem:
问题:
(node:5716) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 message lis
teners added. Use emitter.setMaxListeners() to increase limit.
My code base is huge and i facing this error sometimes i don't know why it is happening
我的代码库很大,有时我会遇到这个错误,我不知道为什么会这样
What I tried :
我试过的:
Tried to increase the listeners limit but unfortunately it is not working.
试图增加听众限制,但不幸的是它不起作用。
const EventEmitter = require('events');
const emitter = new EventEmitter()
emitter.setMaxListeners(50)
UPDATE:
更新:
After Some browsing I run this command to trace wanrning
经过一些浏览后,我运行此命令来跟踪警告
node --trace-warnings index.babel.js
Turns out be my socket.io code is the problem I am using socket.io with redis
原来是我的 socket.io 代码是我在 redis 中使用 socket.io 的问题
this is the error
这是错误
node:14212) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 message li
steners added. Use emitter.setMaxListeners() to increase limit
at _addListener (events.js:281:19)
at RedisClient.addListener (events.js:298:10)
at Namespace.<anonymous> (D:/newProject/services/socket.js:21:17)
at emitOne (events.js:115:13)
at Namespace.emit (events.js:210:7)
at Namespace.emit (D:\newProject\node_modules\socket.io\lib\namespace.js:213:10)
at D:\newProject\node_modules\socket.io\lib\namespace.js:181:14
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
this is the code (But this code is for more specific tasks it will not execute all the time)
这是代码(但此代码用于更具体的任务,它不会一直执行)
const redis = require('redis');
const config = require('../config')
const sub = redis.createClient(config.REDIS.port, config.REDIS.host);
const pub = redis.createClient(config.REDIS.port, config.REDIS.host);
sub.subscribe('spread');
module.exports = io => {
io.on('connection',(socket) => {
let passport = socket.handshake.session.passport; /* To find the User Login */
if(typeof passport !== "undefined") {
socket.on('typing:send',(data) => {
pub.publish('spread',JSON.stringify(data))
});
sub.on('message',(ch,msg) => { // this is the Exact line where I am getting this error
io.emit(`${JSON.parse(msg).commonID}:receive`,{...JSON.parse(msg)})
})
}
});
};
采纳答案by Rohit Harkhani
Default limit for Event Emitteris 10. You can increase it with emitter.setMaxListeners. My suggestion is not to change it unless and until explicitly required, listeners are increased because you didn't unsubscribed. Now to your code.
事件发射器的默认限制为10。您可以使用emitter.setMaxListeners 增加它。我的建议是除非明确要求,否则不要更改它,因为您没有取消订阅,因此听众会增加。现在到你的代码。
const redis = require('redis');
const config = require('../config')
const sub = redis.createClient(config.REDIS.port, config.REDIS.host);
const pub = redis.createClient(config.REDIS.port, config.REDIS.host);
sub.subscribe('spread');
module.exports = io => {
io.on('connection',(socket) => {
//COMMENT : This callback will be executed for all the socket connections.
let passport = socket.handshake.session.passport; /* To find the User Login */
if(typeof passport !== "undefined") {
socket.on('typing:send',(data) => {
pub.publish('spread',JSON.stringify(data))
});
// COMMENT : This is where you are subscribing for each and every socket conected to your server
sub.on('message',(ch,msg) => { // this is the Exact line where I am getting this error
//COMMENT : Where as you are emiting message on socket manager not on socket.
io.emit(`${JSON.parse(msg).commonID}:receive`,{...JSON.parse(msg)})
})
}
});
};
Now if we analyse above code then if you open 20 socket connection to your server it will subscribe for 20 time, here it is going wrong. Now if your requirement is to listen for the message published on redis at server level and then emit on io then your code should be like below
现在,如果我们分析上面的代码,那么如果您打开到服务器的 20 个套接字连接,它将订阅 20 次,这是错误的。现在,如果您的要求是在服务器级别监听在 redis 上发布的消息,然后在 io 上发出,那么您的代码应该如下所示
const redis = require('redis');
const config = require('../config')
const sub = redis.createClient(config.REDIS.port, config.REDIS.host);
const pub = redis.createClient(config.REDIS.port, config.REDIS.host);
sub.subscribe('spread');
module.exports = io => {
sub.on('message',(ch,msg) => { // this is the Exact line where I am getting this error
io.emit(`${JSON.parse(msg).commonID}:receive`,{...JSON.parse(msg)});
});
io.on('connection',(socket) => {
let passport = socket.handshake.session.passport; /* To find the User Login */
if(typeof passport !== "undefined") {
socket.on('typing:send',(data) => {
pub.publish('spread',JSON.stringify(data))
});
}
});
};
回答by flintinatux
The built-in eventsmodule in node.js(a version of which is bundled into your frontend app if you compile with webpackor browserify) makes some assumptions about your code. Sometime, somewhere, somebody decided that if you had Xnumber of listeners registered, then surelyyou've got a memory leak. And sometimes it is correct, and reminds you correctly to go find the leaks.
中的内置events模块node.js(如果您使用webpack或编译,则该模块的版本捆绑到您的前端应用程序中browserify)对您的代码做出一些假设。有时,在某个地方,有人认为如果您X注册了多个侦听器,那么您肯定会出现内存泄漏。有时它是正确的,并正确地提醒您去查找泄漏。
I've received this warning many times, but usually only for two specific reasons, both of which have simple solutions:
我多次收到此警告,但通常只有两个特定原因,两者都有简单的解决方案:
Problem 1: Mismatched bound event listener functions
问题一:绑定事件监听函数不匹配
Your component may look like this, where you are using a component method as the event listener, and you are binding it as you register it.
您的组件可能看起来像这样,您使用组件方法作为事件侦听器,并在注册时绑定它。
import events from '../lib/events' // some singleton event emitter
class MyComponent extends React.Component {
componentDidMount() {
events.addEventListener('some-event', this.myMethod.bind(this))
}
componentWillUnmount() {
events.removeEventListener('some-event', this.myMethod.bind(this))
}
myMethod() {
// does something
}
render() {
// gotta have this too
}
}
The problem here is that function.bindcreates a new functioneach time, such that the function you are trying to remove is not the same as the function you added. Consequently, the added functions keep adding-up (bad pun), and you do in fact have a real memory leak.
这里的问题是每次都会function.bind创建一个新函数,因此您尝试删除的函数与您添加的函数不同。因此,添加的函数不断增加(糟糕的双关语),实际上确实存在内存泄漏。
Solution 1: Bind your methods early
解决方案 1:尽早绑定您的方法
Bind your method early, commonly in the constructor(). Then you can refer to the bound version each time, ensuring that the function removed is the same as the function added.
尽早绑定您的方法,通常在constructor(). 然后每次都可以参考绑定的版本,保证删除的功能和添加的功能一样。
import events from '../lib/events' // some singleton event emitter
class MyComponent extends React.Component {
constructor() {
// bind your method early so the function removed
// is the same as the function added
this.myMethod = this.myMethod.bind(this)
}
componentDidMount() {
events.addEventListener('some-event', this.myMethod)
}
componentWillUnmount() {
events.removeEventListener('some-event', this.myMethod)
}
myMethod() {
// does something
}
render() {
// gotta have this too
}
}
Problem 2: Lots and lots of event listeners
问题 2:大量的事件侦听器
Sometimes you've really done your homework and double-checked that you've bound your listeners early as needed, and then removed them all at the appropriate places. Then you look closer and find that you're doing something like this:
有时你真的做了功课,仔细检查你是否根据需要提前绑定了你的听众,然后在适当的地方把它们全部删除。然后你仔细观察,发现你正在做这样的事情:
import MyComponent from './MyComponent' // same component above
class Parent extends React.Component {
render() {
return (
<div>
{ this.props.largeArray.map(MyComponent) }
</div>
)
}
}
Suppose this.props.largeArrayhad 50, 100, or maybe 250 elements. This means that (by design!) you are rendering 250 instances of MyComponent, each of which is registering another unique event listener.
假设this.props.largeArray有 50、100 或 250 个元素。这意味着(按照设计!)您正在渲染 250 个实例MyComponent,每个实例都注册另一个唯一的事件侦听器。
Fear not! This is totally valid code, and does not have a memory leak. But it does blow through the max-listeners limit that somebody, sometime, somewhere decided arbitrarily to help protect you.
不要怕!这是完全有效的代码,没有内存泄漏。但它确实突破了最大听众数限制,即某人在某个时间、某个地方任意决定帮助保护您。
Solution 2: Switch to using eventemitter3
解决方案2:切换到使用 eventemitter3
If you decide that you've done your homework, and double-checked all the things, and are (by design!) registering lots of event listeners, then the simplest solution is to switch to using eventemitter3, which is a drop-in replacement for node's eventsmodule, except faster, and browser-compatible, and doesn't set a max-listeners limit for you.
如果你决定你已经完成了你的作业,并仔细检查了所有的事情,并且(按照设计!)注册了大量的事件侦听器,那么最简单的解决方案是切换到 using eventemitter3,这是一个直接替代node 的events模块,除了速度更快且与浏览器兼容,并且不会为您设置最大侦听器限制。
Usage is just like the built-in eventsmodule:
用法就像内置events模块:
const EventEmitter = require('eventemitter3')
const emitter = new EventEmitter()
回答by user956584
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11message lis teners added. Use emitter.setMaxListeners() to increase limit
MaxListenersExceededWarning:检测到可能的 EventEmitter 内存泄漏。添加了11 个消息列表。使用emitter.setMaxListeners() 增加限制
By default, a maximum of 10listeners can be registered for any single event, and we got 11Ohno
默认情况下,任何单个事件最多可以注册10 个侦听器,我们得到了11 个Ohno
// Change to 80 or 150 whatever and see what happens
require('events').EventEmitter.prototype._maxListeners = 70;
require('events').defaultMaxListeners = 70;
process.on('warning', function (err) {
if ( 'MaxListenersExceededWarning' == err.name ) {
console.log('o kurwa');
// write to log function
process.exit(1); // its up to you what then in my case script was hang
}
});
回答by Tobiah Rex
This is the recommended way to add and remove event listeners within ReactComponents - using LifeCyclemethods.
这是在React组件中添加和删除事件侦听器的推荐方法- 使用LifeCycle方法。
import { Component } from 'react';
class Example extends Component {
constructor(props) {
super(props);
this.state = {
windowWidth: window.innderWidth,
};
}
componentDidMount() {
window.addEventListener('resize', this.handleResize);
}
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize);
}
handleResize = () => {
this.setState({ windowWidth: window.innerWidth });
}
render() {
return (
<div>
Current window width: {this.state.windowWidth}
</div>
);
}
}
It's important to remember that windowis within the global execution context. Therefore every time you add an event listener, you're asking the global scope to
重要的是要记住这window是在全局执行上下文中。因此,每次添加事件侦听器时,您都是在要求全局范围
- instantiate another listener.
- track that listener using global memory by reference - in this case
resize - continue tracking the listener until told not to.
- 实例化另一个监听器。
- 通过引用使用全局内存跟踪该侦听器 - 在这种情况下
resize - 继续跟踪听众,直到被告知不要这样做。
If you never tell the global scope to remove those listeners, then the global memory - as allocated by your browser settings - will slowly evaporate and crash your browser & application, or the client's browser if already in production. One must be VERY careful and VERY aware when they manipulate global memory.
如果您从不告诉全局范围删除这些侦听器,那么全局内存(由浏览器设置分配)将慢慢蒸发并使您的浏览器和应用程序或客户端浏览器(如果已经在生产中)崩溃。当他们操作全局内存时,必须非常小心和非常清楚。
If you want to understand (if you don't already) WHY the lifecycle methods in React Component's work, I would highly recommend you look hereat React's Reconciliationlifecycle. One can't accurately call themselves a "React Developer"and not be intimately familiar with Reconciliation.
如果您想了解(如果你不这样做的话)为什么在生命周期方法作出反应组件的工作,我会强烈建议你看看这里的阵营的和解生命周期。人们不能准确地称自己为“React 开发人员”,也不能对Reconciliation非常熟悉。
NoteThis Component is using babel to transpile parts of the code: import, and assigned custom method handleResizewith only using arrow functions. If you need assistance in setting up the environment, you can refer to this blog posti wrote that should make it understandable.
注意此组件使用 babel 来转译部分代码:import,并handleResize仅使用箭头函数分配自定义方法。如果您在设置环境方面需要帮助,您可以参考我写的这篇博客文章,它应该可以理解。
Good luck.
祝你好运。

