가능한 EventEmitter 메모리 누출 감지


231

다음과 같은 경고가 나타납니다.

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

이 문제를 해결하는 방법?


46
process.on('warning', e => console.warn(e.stack));경고를 디버그하는 데 사용하십시오 . process.setMaxListeners(0);어떤 이유로 경고가 있으므로 사용하지 마십시오 .
Shwetabh Shekhar

감사합니다. 매우 유용한 지시입니다.
압둘라 알 파 루크

이 오류는에 발생합니다 yarn install. 스택 추적을 추가하기 위해이 줄을 어디에 둘 수 있습니까?
소닉 소울

답변:


94

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

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

요컨대, process.setMaxListeners(0);

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


1
v0.6.11 ... 나는 모든 것을했지만 경고는 여전히 있습니다. :(
Riz

5
사용하고 있습니다process.on('uncaughtException', callback);
Riz

9
process.setMaxListeners(0); // OMG, its so simple... :D
Riz

11
최대 리스너 제한을 제거하지 않습니다. 경고는 없지만 메모리 누수가 발생합니다.

15
이 답변은이 모든 투표를 어떻게 얻었으며 정답으로 선정 되었습니까? 그것은 작동해야하지만 이것은 완전히 잘못입니다!
ProllyGeek

204

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

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


14
+1. 동의했다. 경고는 잠재적 인 누출 상태를 나타내며 maxListeners를 무의식적으로 늘리면 반드시 문제가 해결되는 것은 아닙니다. jongleberry.com/understanding-possible-eventemitter-leaks.html
예레미야 아담스

3
"경고 : 가능한 EventEmitter 메모리 누수가 감지되었습니다. 11 개의 오류 리스너가 추가되었습니다. emitter.setMaxListeners ()를 사용하여 한계를 늘리십시오"를 어떻게 디버그 할 수 있습니까? 무엇을 찾아야합니까?
Phil

2
그러나 해당 오류 메시지와 함께 스택 추적과 코드가 어디에도 없습니다. "Warning"과 "Possible"에 대문자 W와 P가 표시되므로 다른 오류 일 수 있습니다. 하나 이상의 이벤트를 수신해야하지만 모든 경우에 한 번만 .on을 호출하므로 문제가 무엇인지 확실하지 않습니다.
Phil

2
@ Phil_1984_ 해결책을 찾았습니까? -이 제대로 작동하지 않을 경우 stackoverflow.com/questions/38482223/...
요니 여호와

3
참고로 첫 번째 댓글의 링크 (jongleberry.com)는 오프라인 상태입니다. 보관 된 버전은 다음과 같습니다. web.archive.org/web/20180315203155/http://www.jongleberry.com/…
Jeff Ward

76

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

5
이것은 Node 5.6.0에서 나를 위해 일한 유일한 솔루션이었습니다. 정말 감사합니다!
Andrew Faulkner 2016 년

react-native, 노드 버전 8. *. *를 사용하고 있습니다. 이것은 나를 위해 작동하지 않았습니다.
토마스 발라 데스

광산은 require ( 'events')입니다. EventEmitter.defaultMaxListeners = 무한대;
Karl Anthony Baluyot '

73

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


13
이 답변은 경고의 실제 이유와 해결 방법을 보여주기 때문에 받아 들여야합니다. +1
Ganesh Karewad

이것은 올바른 답변입니다! 솔직히 maxListener 경고는 대부분 버그가 있기 때문에 나타납니다. 제 경우에는 mysql 코드였습니다. 나는 그것을 명확하게하기 위해 대답을하려고 노력할 것입니다.
Adrian

25

교체 .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이 업데이트 아직, 그러나.


이 코드는 Puppeterr 프레임 워크를 사용하여 내 코드에서이 오류를 수정합니다.
C Alonso C Ortega


4

노드 버전 : 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가 알림을 지울 것으로 기대했습니다.


2

제 경우에는 child.stderr.pipe(process.stderr)10 번 (또는 그 이상)의 어린이 인스턴스를 시작할 때 호출되었습니다. 따라서 이벤트 핸들러를 LOOP의 동일한 EventEmitter 오브젝트에 첨부하게되면 nodejs가이 오류를 발생시킵니다.


2

때때로 이러한 경고는 우리가 한 것이 아니라 잊어 버린 것이 될 때 발생합니다!

npm으로 dotenv 패키지를 설치할 때이 경고가 발생했지만 앱 시작 부분에 require ( 'dotenv'). load () 문을 추가하기 전에 중단되었습니다. 프로젝트로 돌아 왔을 때 "Possible EventEmitter memory leak detected"경고가 표시되기 시작했습니다.

나는 문제가 내가 한 것이 아니라 내가 한 것이 아니라고 가정했다!

내 감독을 발견하고 require 문을 추가하면 메모리 누수 경고가 사라졌습니다.


2

가능할 때마다 로그를 표시하지 않고 문제를 찾아 해결하는 것을 선호합니다. 내 앱 에서이 문제를 관찰 한 후 며칠 후 req.socketExpress 미들웨어에서 리스너를 설정하여 계속해서 나타나는 소켓 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();
    }

해당 미들웨어를 제거하면보고있는 경고가 중지되었습니다. 코드를 둘러보고 필요하지 않은 청취자를 설정할 수있는 곳을 찾으려고합니다.


1

나는 같은 문제가 있었다. 2 개의 리스너에서 포트 8080을 듣고 있기 때문에 문제가 발생했습니다.

setMaxListeners() 잘 작동하지만 권장하지는 않습니다.

올바른 방법은 코드에 추가 리스너가 있는지 확인하고 리스너를 제거하거나 청취중인 포트 번호를 변경하는 것입니다. 이는 내 문제를 해결했습니다.


1

나는 오늘 시작할 때까지 이것을 가지고 있었다 grunt watch. 마지막으로 해결

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

성가신 메시지가 사라졌습니다.


1

다음을 사용하여 새 리스너를 작성하기 전에 모든 리스너를 지워야합니다.

클라이언트 서버

socket.removeAllListeners(); 

socket이 클라이언트 소켓이거나 생성 된 서버 소켓이라고 가정합니다.

예를 들어 다음 connect과 같이 리스너 를 제거하는 등의 특정 이벤트 리스너를 구독 할 수도 있습니다 .

this.socket.removeAllListeners("connect");

0

process.on('uncaughtException', callback);
이 문장 을 어디에서 실행하고 있습니까? 콜백 내에 전달 http.createServer되었습니까?
그렇다면, 같은 콜백의 다른 사본이 첨부 얻을 것이다 의 uncaughtException의 (가) 때문에, 각각의 새로운 요청에 따라 이벤트 function (req, res) { ... }실행마다를 얻는 새로운 요청이 들어오고 그래서 것이다 문 process.on('uncaughtException', callback);
있습니다 프로세스 개체가 전역 모든 요청과 추가 청취자에게 새로운 요청이 올 때마다 이벤트에 아무런 의미가 없습니다. 그런 행동을 원하지 않을 수도 있습니다.
새 요청마다 새 리스너를 연결하려면 다음을 사용하여 더 이상 필요하지 않으므로 이벤트에 연결된 모든 이전 리스너를 제거해야합니다.
process.removeAllListeners('uncaughtException');


0

우리 팀의 수정은 .npmrc에서 레지스트리 경로를 제거하는 것이 었습니다. rc 파일에는 두 개의 경로 별칭이 있었고, 하나는 더 이상 사용되지 않는 Artifactory 인스턴스를 가리 켰습니다.

이 오류는 우리의 응용 프로그램의 실제 코드와는 아무하지만이 없었다 모든 우리의 개발 환경을 함께 할 수 있습니다.


0

나는 같은 문제에 직면했지만 async await로 성공적으로 처리했습니다.
도움이되는지 확인하십시오.

dataLength = 25;
이전 :
  for (let i = 0; i <dataLength; i ++) {
      sftp.get (remotePath, fs.createWriteStream ( xyzProject/${data[i].name}));
  }

후 :
  for (let i = 0; i <dataLength; i ++) {
      await sftp.get (remotePath, fs.createWriteStream ( xyzProject/${data[i].name}));
  }


0

RLaaa 에게 감사합니다경고의 실제 문제 / 근본 원인을 해결하는 방법을 알려 주신 에게 . 내 경우에는 MySQL 버그 코드였습니다.

다음과 같은 코드를 사용하여 Promise를 작성했습니다.

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')청취자를 제거 하고 짜잔 ... 해결! 이것이 도움이되기를 바랍니다.


-4

이것을 server.js의 첫 번째 줄 (또는 기본 Node.js 앱이 포함 된 모든 항목)에 넣으십시오.

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

오류가 사라집니다 :)


주 파일에 넣을 아이디어를 주었고 효과가있었습니다. 방금 잘못된 장소에 넣었습니다. 감사!
sklimkovitch
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.