[node.js] 가능한 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);

이 문제를 해결하는 방법?



답변

이것은 노드 eventEmitter 문서 에서 설명됩니다

어떤 버전의 노드입니까? 다른 코드가 있습니까? 그것은 정상적인 행동이 아닙니다.

요컨대, process.setMaxListeners(0);

참조 : node.js-요청-“emitter.setMaxListeners ()”방법?


답변

나는 여기에 경고가 이유가 있기 때문에 올바른 수정이 이루어 지지 않을 가능성이 있음을 지적하고 싶습니다. 한계를 증가하지만 같은 이벤트에 많은 청취자를 추가하는 이유를 알아내는가. 너무 많은 청취자가 추가되는 이유를 알고 정말로 원하는 청취자 인 경우에만 한계를 늘리십시오.

이 경고가 나타났기 때문에이 페이지를 찾았습니다. 내 경우에는 전역 객체를 EventEmitter로 바꾸는 데 사용중인 일부 코드에 버그가있었습니다! 나는 당신이 이러한 것들을 눈에 띄지 않기를 원하지 않기 때문에 전 세계적으로 한계를 늘리지 말 것을 권고합니다.


답변

기본적으로 단일 이벤트에 최대 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;

BTW. 코드는 앱의 시작 부분에 있어야합니다.

ADD : 노드 0.11부터이 코드는 기본 제한을 변경하기 위해 작동합니다.

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


답변

허용 된 답변은 한계를 늘리는 방법에 대한 의미를 제공하지만 @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를 변경하기 전에 코드에서 비슷한 문제를 검색하십시오 (다른 답변에서 설명 함).


답변

교체 .on()와 함께 once(). 사용once() 하면 이벤트가 동일한 기능으로 처리 될 때 이벤트 리스너가 제거됩니다.

이 방법으로 문제가 해결되지 않으면 package.json “restler”에 “rest : //”를 설치하십시오. “git : //github.com/danwrong/restler.git#9d455ff14c57ddbe263dbbcd0289d76413bfe07d”

이것은 노드에서 오작동하는 restler 0.10과 관련이 있습니다. : 당신은 문제가 여기 자식에 폐쇄 볼 수 https://github.com/danwrong/restler/issues/112을
당신이 자식 머리를 참조해야 할 이유가 그래서, NPM이 업데이트 아직, 그러나.


답변

Mac OSX에 aglio를 설치할 때도이 경고가 표시됩니다.

cmd를 사용하여 수정하십시오.

sudo npm install -g npm@next

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


답변

노드 버전 : 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.shutdown ()을 호출해야합니다.

알림을 보낼 때마다 공급자 객체를 만들고 있었고 gc가 알림을 지울 것으로 기대했습니다.