NodeJS:如何调试“检测到EventEmitter内存泄漏。添加了11个侦听器”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15581978/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 13:58:46  来源:igfitidea点击:

NodeJS : How to debug "EventEmitter memory leak detected. 11 listeners added"

node.jsmemory-leakseventemitter

提问by Ifnot

How can I debug my application which throw this error:

如何调试抛出此错误的应用程序:

(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace
    at Socket.EventEmitter.addListener (events.js:160:15)
    at Socket.Readable.on (_stream_readable.js:653:33)
    at Socket.EventEmitter.once (events.js:179:8)
    at TCP.onread (net.js:527:26)

I could not find the assumed leaking object for increasing listener limit by .setMaxListeners(0);

我找不到用于增加侦听器限制的假定泄漏对象 .setMaxListeners(0);

SOLUTION (from fardjad and jan salawa)

解决方案(来自 fardjad 和 jan salawa)

With jan salawa's searches I found a working library (longjohn) for increasing stack traces verbose. With fardjad's response I have found that we have to prototype EventEmitter.addListenerANDEventEmitter.on.

通过 jan salawa 的搜索,我找到了一个工作库(longjohn),用于增加详细的堆栈跟踪。通过 fardjad 的回应,我发现我们必须对EventEmitter.addListenerAND进行原型设计EventEmitter.on

With the solution I could get this new trace:

通过解决方案,我可以获得这个新的跟踪:

(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace
    at EventEmitter.addListener.EventEmitter.on (xxx/main.js:44:15)
    at Readable.on (_stream_readable.js:653:33)
    at ServerResponse.assignSocket (http.js:1072:10)
    at parser.onIncoming (http.js:1979:11)
    at parserOnHeadersComplete (http.js:119:23)
    at socket.ondata (http.js:1912:22)
    at TCP.onread (net.js:510:27)

采纳答案by Ifnot

It turns out that this is a bug in nodejs core, we are talking about this problem here : https://github.com/joyent/node/issues/5108

原来这是nodejs核心的一个bug,我们在这里讨论这个问题:https: //github.com/joyent/node/issues/5108

Solution for bugged http servers thats throw an EventEmitter memory leak detectedand fill up the available memory / available CPU times :

错误的 http 服务器的解决方案是抛出EventEmitter memory leak detected并填满可用内存/可用 CPU 时间:

Revert to legacy version v0.8.23. (You can download and install/compile it from here : http://blog.nodejs.org/2013/04/08/node-v0-8-23-legacy/)

恢复到旧版本v0.8.23。(你可以从这里下载和安装/编译它:http: //blog.nodejs.org/2013/04/08/node-v0-8-23-legacy/

UPDATE 2018 :I see several feedbacks on this topic whereas the problem looks to be gone since years. Note that this response is only for a leaking http server build with nodejs. If you are in other scenario, please look the others responses on this thread and dont downgrade your version (as suggested on this response), you will waste your time.

2018 年更新:我看到一些关于这个主题的反馈,而这个问题多年来似乎已经消失了。请注意,此响应仅适用于使用 nodejs 构建泄漏的 http 服务器。如果您处于其他情况,请查看此线程上的其他回复,不要降级您的版本(如本回复中所建议的那样),您会浪费时间。

回答by jan salawa

For me it's looks like your event loop is blocked. This can happen if you are doing cpu intensive tasks in node.js event loop. You can use child processto do intensive task.

对我来说,您的事件循环似乎被阻止了。如果您在 node.js 事件循环中执行 CPU 密集型任务,就会发生这种情况。您可以使用子进程来完成密集型任务。

You can check what is blocking node.js using following methods:

您可以使用以下方法检查阻塞 node.js 的内容

  1. Measure computation timeof each call. Log if time is high so you know app is misbehaving.
  2. Set up a log schedule so you know when something blocking loop
    function timeTick() {
        var startTime = (new Date().getTime());
        function onTick() {
            var interval = (new Date().getTime()) - startTime;
            if(interval > 5)
                console.log('timeTick(): WARNING: interval = ' + interval);
        }
       process.nextTick(onTick);
    }
    setInterval(timeTick, 1000);
  3. Use profile.
  4. Use thisfor logging and profiling. It's library used in Nodejitsu.
  1. 测量每次调用的计算时间。如果时间很长,请记录,以便您知道应用程序行为不端。
  2. 设置日志计划,以便您知道何时阻塞循环
    function timeTick() {
        var startTime = (new Date().getTime());
        function onTick() {
            var interval = (new Date().getTime()) - startTime;
            if(interval > 5)
                console.log('timeTick(): WARNING: interval = ' + interval);
        }
       process.nextTick(onTick);
    }
    setInterval(timeTick, 1000);
  3. 使用配置文件。
  4. 使用进行日志记录和分析。它是Nodejitsu 中使用的库。

回答by fadleen

This is exactly what happened to me. For me, I nested an event listener within another event listener accidentally.

这正是发生在我身上的事情。对我来说,我不小心将一个事件侦听器嵌套在另一个事件侦听器中。

Look at your code and make sure you DO NOT have an event listener block WITHIN another event listener block for example(unless you are doing it on purpose):

查看您的代码并确保您没有在另一个事件侦听器块中包含一个事件侦听器块,例如(除非您是故意这样做的):

socket.on('data', function(data) {
//code goes here

socket.on('close' , function() {
//code goes here
     });

   });

In the wrong example above, the socket.on ('close') listener should be OUTSIDE of the socket.on('data') block.

在上面的错误示例中,socket.on ('close') 侦听器应该在 socket.on('data') 块之外。

In my case when I received 5 data streams, the socket.on('close') listener is waiting for a close event to happen. When I close once, another 4th closing event would execute. This is clearly not what I wanted. This is due to the nature of Node.js which is non-blocking. It 'remembers' events due to the callback function.

就我而言,当我收到 5 个数据流时,socket.on('close') 侦听器正在等待关闭事件发生。当我关闭一次时,将执行另一个第四个关闭事件。这显然不是我想要的。这是由于 Node.js 的非阻塞性质。由于回调函数,它“记住”事件。

回答by nicojs

Since node 6 you should use node --trace-warnings: https://nodejs.org/api/cli.html#cli_trace_warnings

从节点 6 开始,您应该使用node --trace-warningshttps: //nodejs.org/api/cli.html#cli_trace_warnings

回答by fardjad

I tried to prototype the EventEmitter for adding log messages into addListener but i could not get it working

我尝试将 EventEmitter 原型化以将日志消息添加到 addListener 中,但我无法让它工作

To hook addListeneryou can do something like this:

要挂钩,addListener您可以执行以下操作:

// on the first line of your main script
var events = require("events"),
    EventEmitter = events.EventEmitter;

var originalAddListener = EventEmitter.prototype.addListener;
EventEmitter.prototype.addListener = function (type, listener) {
    if (this.listenerCount(this, type) >= 10) {
        // TODO: PLACE YOUR CODE FOR DEBUGGING HERE
    }
    originalAddListener.apply(this, arguments);
}

回答by Vishwanath gowda k

This warning will be thrown if you register for a particular event of a same object more than 11 times.

如果您注册同一对象的特定事件超过 11 次,则会抛出此警告。

Check if you are having 'on' call for particualr event in a function which you are calling frequently, this leads to registering for an event multiple times.

检查您是否在经常调用的函数中对特定事件进行“开启”调用,这会导致多次注册一个事件。

Thislink helped me to understand this.

这个链接帮助我理解了这一点。

回答by pushkin

I was seeing this when I was running my unit tests. My unit tests were repeatedly calling code that was calling:

我在运行单元测试时看到了这一点。我的单元测试反复调用正在调用的代码:

process.on("uncaughtException", () => { ... });

I had to use dependency injection to inject a fake process object, which solved the problem.

我不得不使用依赖注入来注入一个假进程对象,从而解决了问题。

main.js:

主要.js:

export function main(myProcess) {
    myProcess.on("uncaughtException", () => { ... });
}

if (require.main === module) { // to prevent this from executing when running unit tests
    main(process);
}

My unit tests would do:

我的单元测试会做:

const fakeProcess = jasmine.createSpy("process", ["on"]);
main(fakeProcess);

回答by brendangibson

I ran into the same problem when testing Reactcomponents using mochaand enzyme.

我在使用mocha测试React组件时遇到了同样的问题。

I was able to solve my problem by explicitly unmounting components after I had finished testing them.

在完成测试后,我能够通过明确卸载组件来解决我的问题。

The issue was that I was mounting components multiple times in my tests, which were then adding more listeners, until the number of listeners got to 11, and I got a warning.

问题是我在测试中多次安装组件,然后添加更多侦听器,直到侦听器数量达到 11,我收到警告。

I changed my test code by adding the rendered.unmount()line. This fixed the problem for me.

我通过添加render.unmount()行更改了我的测试代码。这为我解决了问题。

describe('<CircleArc />', () => {

    it('renders', function () {
        const rendered = mount(<CircleArc />);
        assert.ok(rendered.find('path'));
        rendered.unmount();
    });
}