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 ?


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


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.


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

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)


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.


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


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.


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.


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.


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.


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.


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.


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

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


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.


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


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ê.


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


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.