possível vazamento de memória EventEmitter detectado

231

Estou recebendo o seguinte aviso:

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

Eu escrevi um código como este no server.js:

http.createServer(
    function (req, res) { ... }).listen(3013);

Como consertar isto ?

Riz
fonte
46
Use process.on('warning', e => console.warn(e.stack));para depurar o aviso. Não use, process.setMaxListeners(0);pois o aviso existe por algum motivo.
Shwetabh Shekhar
Obrigado. instrução muito útil.
Abdullah Al Farooq
esse erro acontece comigo em yarn install. Onde posso colocar esta linha para adicionar rastreamento de pilha?
Sonic Soul

Respostas:

94

Isso é explicado na documentação do evento de nó

Que versão do Node é essa? Que outro código você tem? Esse não é um comportamento normal.

Em suma, é: process.setMaxListeners(0);

Veja também: node.js - request - Como “emitter.setMaxListeners ()”?

Corey Richardson
fonte
1
v0.6.11 ... Eu fiz tudo, mas o aviso ainda está lá. :(
Riz
5
Eu estou usandoprocess.on('uncaughtException', callback);
Riz
9
process.setMaxListeners(0); // OMG, its so simple... :D
Riz
11
Eu não removeria o limite máximo de ouvinte. Você não receberá avisos, mas haverá vazamentos de memória.
15
Como essa resposta obteve todos esses votos positivos e foi escolhida como resposta correta? mesmo que funcione, mas isso está completamente errado !!
ProllyGeek
204

Gostaria de salientar aqui que esse aviso existe por um motivo e há uma boa chance de a correção correta não aumentar o limite, mas descobrir por que você está adicionando tantos ouvintes ao mesmo evento. Aumente o limite apenas se você souber por que tantos ouvintes estão sendo adicionados e estiver confiante de que é isso que você realmente deseja.

Encontrei esta página porque recebi esse aviso e, no meu caso, havia um bug em algum código que estava usando que estava transformando o objeto global em um EventEmitter! Eu certamente desaconselharia a aumentar o limite globalmente, porque você não quer que essas coisas passem despercebidas.

voltrevo
fonte
14
+1. Acordado. O aviso indica um possível estado de vazamento e o aumento irracional dos maxListeners não solucionará necessariamente o problema. jongleberry.com/understanding-possible-eventemitter-leaks.html
Jeremiah Adams
3
Como você pode depurar "Aviso: possível detecção de vazamento de memória do EventEmitter. 11 ouvintes de erro foram adicionados. Use emitter.setMaxListeners () para aumentar o limite". O que devemos procurar?
Phil
2
Mas não há rastreamento de pilha nem código em nenhum lugar com essa mensagem de erro. Recebo letras maiúsculas W e P em "Warning" e "Possible", então acho que pode ser um erro diferente. Eu preciso de mais de um evento escutado, mas só ligo para. Uma vez em todos os casos, para não ter certeza de qual é o problema.
22416 Phil
2
@ Phil_1984_ Você encontrou uma solução? Se não, isso parece funcionar - stackoverflow.com/questions/38482223/…
Yoni Jah
3
Para sua informação, o link do primeiro comentário (jongleberry.com) está offline. Aqui está a versão arquivada: web.archive.org/web/20180315203155/http://www.jongleberry.com/...
Jeff Ward
76

Por padrão, um máximo de 10 ouvintes podem ser registrados para qualquer evento único.

Se for o seu código, você pode especificar maxListeners via:

const emitter = new EventEmitter()
emitter.setMaxListeners(100)
// or 0 to turn off the limit
emitter.setMaxListeners(0)

Mas se não for o seu código, você pode usar o truque para aumentar o limite padrão globalmente:

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

Claro que você pode desativar os limites, mas tenha cuidado:

// turn off limits by default (BE CAREFUL)
require('events').EventEmitter.prototype._maxListeners = 0;

Entre. O código deve estar no início do aplicativo.

ADD: Desde o nó 0.11, este código também funciona para alterar o limite padrão:

require('events').EventEmitter.defaultMaxListeners = 0
zag2art
fonte
5
Essa foi a única solução que funcionou para mim no nó 5.6.0. Muito obrigado!
Andrew Faulkner
Estou usando o react-native, versão do nó 8. *. *. Isso não funcionou para mim.
Thomas Valadez 25/10
o meu era require ('events'). EventEmitter.defaultMaxListeners = Infinity;
Karl Anthony Baluyot
73

A resposta aceita fornece a semântica de como aumentar o limite, mas como o @voltrevo apontou que o aviso existe por um motivo e seu código provavelmente tem um bug.

Considere o seguinte código de buggy:

//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');
}

Agora observe a maneira correta de adicionar o ouvinte:

//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');
}

Pesquise problemas semelhantes no seu código antes de alterar os maxListeners (o que é explicado em outras respostas)

Rayee Roded
fonte
13
esta resposta deve ser aceita, pois mostra o motivo real do aviso e como resolvê-lo, +1
Ganesh Karewad
Essa é a resposta correta! Sinceramente, acho que o aviso maxListener aparece principalmente por causa de alguns códigos de buggy. No meu caso, era o código mysql. Vou tentar responder apenas para esclarecer isso.
Adrian
25

Substitua .on()por once(). O uso once()remove ouvintes de eventos quando o evento é tratado pela mesma função.

Se isso não corrigir, reinstale o restler com isso no package.json "restler": "git: //github.com/danwrong/restler.git#9d455ff14c57ddbe263dbbcd0289d76413bfe07d"

Isso tem a ver com o restler 0.10 se comportando mal com o nó. você pode ver o problema encerrado no git aqui: https://github.com/danwrong/restler/issues/112 No entanto, o npm ainda não atualizou isso; é por isso que você deve consultar o cabeçalho do git.

Davis Dulin
fonte
isso corrige esse erro no meu código usando o framework Puppeterr
C Alonso C Ortega
5

Estou recebendo esse aviso também ao instalar o aglio no meu mac osx.

Eu uso o cmd corrigi-lo.

sudo npm install -g npm@next

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

Legolas Bloom
fonte
4

Versão do nó: v11.10.1

Mensagem de aviso do rastreamento de pilha:

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)

Após procurar por problemas no github, documentação e criar vazamentos de memória do emissor de eventos semelhantes, esse problema foi observado devido ao módulo node-apn usado para a notificação por push do iOS.

Isso resolveu:

Você deve criar apenas um provedor por processo para cada par de certificado / chave que tiver. Você não precisa criar um novo provedor para cada notificação. Se você estiver enviando notificações apenas para um aplicativo, não será necessário mais de um provedor.

Se você estiver constantemente criando instâncias do provedor em seu aplicativo, chame Provider.shutdown () quando terminar com cada provedor para liberar seus recursos e memória.

Eu estava criando um objeto de provedor toda vez que a notificação era enviada e esperava que o gc a limpasse.

Sandeep PC
fonte
2

No meu caso, era o child.stderr.pipe(process.stderr)que estava sendo chamado quando eu estava iniciando 10 (mais ou menos) instâncias da criança. Portanto, qualquer coisa que leve a anexar um manipulador de eventos ao mesmo objeto EventEmitter em um LOOP faz com que o nodejs gere esse erro.

Vikas Gautam
fonte
2

Às vezes, esses avisos ocorrem quando não é algo que fizemos, mas que esquecemos de fazer!

Encontrei esse aviso quando instalei o pacote dotenv com o npm, mas fui interrompido antes de adicionar a instrução require ('dotenv'). Load () no início do meu aplicativo. Quando voltei ao projeto, comecei a receber os avisos "Possível vazamento de memória do EventEmitter detectado".

Eu assumi que o problema era de algo que eu tinha feito, não algo que eu não tinha feito!

Depois que descobri minha supervisão e adicionei a declaração de exigência, o aviso de vazamento de memória foi apagado.

Motate
fonte
2

Prefiro caçar e corrigir problemas em vez de suprimir logs sempre que possível. Após alguns dias observando esse problema no meu aplicativo, percebi que estava configurando ouvintes no req.socketmiddleware Express para detectar erros de soquete io que continuavam aparecendo. Em algum momento, aprendi que isso não era necessário, mas mantive os ouvintes por perto. Acabei de removê-los e o erro que você está enfrentando desapareceu. Eu verifiquei que era a causa executando solicitações ao meu servidor com e sem o seguinte middleware:

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

A remoção desse middleware interrompeu o aviso que você está vendo. Examinaria seu código e tentaria encontrar qualquer lugar em que você possa configurar ouvintes que você não precisa.

lwdthe1
fonte
1

Eu estava tendo o mesmo problema. e o problema foi causado porque eu estava ouvindo a porta 8080, em 2 ouvintes.

setMaxListeners() funciona bem, mas eu não recomendo.

a maneira correta é, verifique o seu código para ouvir mais ouvintes, remova o ouvinte ou altere o número da porta em que você está ouvindo, isso corrigiu o meu problema.

Noman Abid
fonte
1

Eu estava tendo isso até hoje quando começo grunt watch. Finalmente resolvido por

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

A mensagem irritante se foi.

Ariful Haque
fonte
1

Você precisa limpar todos os ouvintes antes de criar novos usando:

Servidor cliente

socket.removeAllListeners(); 

Supondo que o soquete é o soquete do cliente / ou o soquete do servidor criado.

Você também pode se inscrever em ouvintes de eventos específicos, como por exemplo, removendo o connectouvinte assim:

this.socket.removeAllListeners("connect");
ProllyGeek
fonte
0

Você disse que está usando process.on('uncaughtException', callback);
Onde está executando esta declaração? É dentro do retorno de chamada passado para http.createServer?
Se sim, uma cópia diferente do mesmo retorno de chamada será anexada ao evento uncaughtException a cada nova solicitação, porque ela function (req, res) { ... }é executada toda vez que uma nova solicitação é recebida e a instrução process.on('uncaughtException', callback);
Observe que o objeto do processo é global para todas as suas solicitações e adicionando ouvintes ao evento toda vez que uma nova solicitação entrar, não fará sentido. Você pode não querer esse tipo de comportamento.
Caso deseje anexar um novo ouvinte para cada nova solicitação, remova todos os ouvintes anteriores anexados ao evento, pois eles não serão mais necessários usando:
process.removeAllListeners('uncaughtException');

Monish Chhadwa
fonte
0

A correção da nossa equipe foi remover um caminho de registro do nosso .npmrc. Tínhamos dois aliases de caminho no arquivo rc e um estava apontando para uma instância Artifactory que havia sido descontinuada.

O erro não tinha nada a ver com o código real do nosso aplicativo, mas tudo a ver com o nosso ambiente de desenvolvimento.

RossO
fonte
0

Eu estava enfrentando o mesmo problema, mas resolvi com êxito aguardar async.
Por favor, verifique se ajuda.

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

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

Vivek Mehta
fonte
0

Agradeço ao RLaaa por me dar uma idéia de como resolver o verdadeiro problema / causa raiz do aviso. Bem, no meu caso, era o código de bugs do MySQL.

Fornecendo que você escreveu uma promessa com um código como este:

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

Observe que há um conn.on('error')ouvinte no código. Esse código literalmente adicionando ouvinte repetidamente depende de quantas vezes você chama a consulta. Enquanto isso, if(err) reject(err)faz a mesma coisa.

Então tirei o conn.on('error')ouvinte e pronto ... resolvi! Espero que isso ajude você.

Adrian
fonte
-4

Coloque isso na primeira linha do seu server.js (ou qualquer outro que contenha seu aplicativo principal do Node.js.):

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

e o erro desaparece :)

Sebastian
fonte
Você me deu uma idéia para colocá-lo em um arquivo principal e funcionou. Eu estava apenas colocando em um lugar errado. Obrigado!
precisa saber é o seguinte