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

时间:2013-03-23 00:35:14

标签: node.js memory-leaks eventemitter

如何调试导致此错误的应用程序:

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

我无法通过.setMaxListeners(0);

找到用于增加侦听器限制的假定泄漏对象

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

通过jan salawa的搜索,我找到了一个工作库(longjohn)来增加堆栈跟踪的详细信息。根据fardjad的回复,我发现我们必须对EventEmitter.addListener AND EventEmitter.on进行原型设计。

通过该解决方案,我可以得到这个新的痕迹:

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

8 个答案:

答案 0 :(得分:31)

事实证明这是nodejs核心中的一个错误,我们在这里讨论这个问题:https://github.com/joyent/node/issues/5108

有问题的http服务器的解决方案,它会抛出EventEmitter memory leak detected并填满可用内存/可用CPU时间:

恢复旧版v0.8.23。 (您可以从此处下载并安装/编译它:http://blog.nodejs.org/2013/04/08/node-v0-8-23-legacy/

更新2018年:我看到有关此主题的几个反馈,而问题似乎已经消失多年了。请注意,此响应仅适用于使用nodejs泄漏的http服务器。如果您在其他情况下,请查看其他人对此主题的回复并且不要降级您的版本(如此回复中所建议的那样),您将浪费时间。

答案 1 :(得分:12)

对我来说,看起来你的事件循环被阻止了。如果您在node.js事件循环中执行cpu密集型任务,则会发生这种情况。您可以使用child process执行密集型任务。

您可以使用following methods检查阻止node.js的内容:

    每次通话的
  1. Measure computation time。如果时间很长,请记录,以便知道app是行为不端。
  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. 使用profile.
  4. 使用this进行日志记录和分析。它是 Nodejitsu 中使用的库。

答案 2 :(得分:10)

这正是发生在我身上的事。对我来说,我意外地在另一个事件监听器中嵌套了一个事件监听器。

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

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

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

   });

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

在我收到5个数据流的情况下,socket.on(' close')监听器正在等待关闭事件发生。当我关闭一次时,将执行另一个第四次结束事件。这显然不是我想要的。这是由于Node.js的性质是非阻塞的。它记得'由回调函数引起的事件。

答案 3 :(得分:5)

  

我尝试将EventEmitter原型化为添加日志消息   addListener但我无法使其正常工作

要挂钩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);
}

答案 4 :(得分:5)

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

检查您是否正在使用'在您经常调用的函数中调用particalr事件,这会导致多次注册事件。

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

答案 5 :(得分:1)

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

答案 6 :(得分:0)

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

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

我不得不使用依赖注入来注入伪造的流程对象,从而解决了问题。

main.js:

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

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

我的单元测试可以:

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

答案 7 :(得分:-1)

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

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

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

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

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

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