rilevata perdita di memoria EventEmitter


231

Ricevo il seguente avviso:

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

Ho scritto codice come questo in server.js:

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

Come risolvere questo?


46
Utilizzare process.on('warning', e => console.warn(e.stack));per eseguire il debug dell'avviso. Non utilizzare process.setMaxListeners(0);come l'avviso è lì per qualche motivo.
Shwetabh Shekhar,

Grazie. istruzioni molto utili.
Abdullah Al Farooq,

questo errore mi succede su yarn install. dove posso mettere questa riga per aggiungere la traccia dello stack?
Sonic Soul,

Risposte:


94

Questo è spiegato nella documentazione del nodo eventEmitter

Quale versione di Node è questa? Quale altro codice hai? Non è un comportamento normale.

In breve, è: process.setMaxListeners(0);

Vedi anche: node.js - richiesta - Come "emitter.setMaxListeners ()"?


1
v0.6.11 ... Ho fatto tutto, ma l'avvertimento è ancora lì. :(
Riz

5
Sto usandoprocess.on('uncaughtException', callback);
Riz

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

11
Non rimuoverei il limite massimo di listener. Non riceverai avvisi, ma otterrai perdite di memoria.

15
In che modo questa risposta ha ottenuto tutti questi voti positivi ed è stata scelta come risposta corretta? anche se dovrebbe funzionare, ma questo è completamente sbagliato !!
ProllyGeek,

204

Vorrei sottolineare qui che quell'avvertimento è lì per una ragione e che ci sono buone probabilità che la soluzione giusta non aumenti il ​​limite ma capisca perché stai aggiungendo così tanti ascoltatori allo stesso evento. Aumenta il limite solo se sai perché vengono aggiunti così tanti ascoltatori e sei sicuro che sia ciò che desideri davvero.

Ho trovato questa pagina perché ho ricevuto questo avviso e nel mio caso c'era un bug in qualche codice che stavo usando che stava trasformando l'oggetto globale in un EventEmitter! Sicuramente sconsiglio di aumentare il limite a livello globale perché non vuoi che queste cose passino inosservate.


14
+1. Concordato. L'avvertimento indica il potenziale stato di perdita e l'aumento senza senso dei maxListener non risolverà necessariamente il problema. jongleberry.com/understanding-possible-eventemitter-leaks.html
Jeremiah Adams

3
Come si può eseguire il debug "Avvertenza: rilevata possibile perdita di memoria EventEmitter. Aggiunti 11 listener di errori. Utilizzare emitter.setMaxListeners () per aumentare il limite". Cosa dovremmo cercare?
Phil

2
Ma non c'è traccia dello stack e nessun codice ovunque con quel messaggio di errore. Ottengo W e P maiuscoli su "Avvertenza" e "Possibile", quindi penso che potrebbe essere un errore diverso. Ho bisogno di più di un evento ascoltato, ma chiamo sempre e solo una volta in tutti i casi, quindi non sono sicuro di quale sia il problema.
Phil,

2
@ Phil_1984_ Hai trovato una soluzione? in caso contrario questo sembra funzionare - stackoverflow.com/questions/38482223/…
Yoni Jah

3
Cordiali saluti, il link del primo commento (jongleberry.com) non è in linea. Ecco la versione archiviata: web.archive.org/web/20180315203155/http://www.jongleberry.com/…
Jeff Ward,

76

Per impostazione predefinita, è possibile registrare un massimo di 10 ascoltatori per ogni singolo evento.

Se è il tuo codice, puoi specificare maxListeners tramite:

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

Ma se non è il tuo codice puoi usare il trucco per aumentare il limite predefinito a livello globale:

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

Ovviamente puoi disattivare i limiti ma fai attenzione:

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

BTW. Il codice dovrebbe essere all'inizio dell'app.

AGGIUNGI: dal nodo 0.11 questo codice funziona anche per modificare il limite predefinito:

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

5
Questa è stata l'unica soluzione che ha funzionato per me nel Nodo 5.6.0. Grazie mille!
Andrew Faulkner,

Sto usando il nodo di reazione nativo, versione 8. *. *. Questo non ha funzionato per me.
Thomas Valadez,

il mio era richiesto ("eventi"). EventEmitter.defaultMaxListeners = Infinity;
Karl Anthony Baluyot,

73

La risposta accettata fornisce la semantica su come aumentare il limite, ma come ha sottolineato @voltrevo che l'avviso è presente per un motivo e il codice probabilmente ha un bug.

Considera il seguente codice 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');
}

Ora osserva il modo corretto di aggiungere l'ascoltatore:

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

Cerca problemi simili nel tuo codice prima di modificare maxListeners (che è spiegato in altre risposte)


13
questa risposta dovrebbe essere accettata in quanto mostra il vero motivo dietro l'avvertimento e come risolverlo, +1
Ganesh Karewad,

Questa è la RISPOSTA CORRETTA! Sinceramente penso che l'avviso maxListener appaia principalmente a causa di alcuni codici errati. Nel mio caso era il codice mysql. Cercherò di dare una risposta solo per chiarire questo.
Adrian

25

Sostituisci .on()con once(). L'uso once()rimuove i listener di eventi quando l'evento è gestito dalla stessa funzione.

Se questo non lo risolve, quindi reinstallare restler con questo nel tuo pacchetto.json "restler": "git: //github.com/danwrong/restler.git#9d455ff14c57ddbe263dbbcd0289d76413bfe07d"

Ciò ha a che fare con il restler 0,10 che si comporta male con il nodo. puoi vedere il problema chiuso su git qui: https://github.com/danwrong/restler/issues/112 Tuttavia, npm non ha ancora aggiornato questo, quindi è per questo che devi fare riferimento alla testa di git.


risolto questo errore sul mio codice usando il framework Puppeterr
C Alonso C Ortega


4

Versione nodo: v11.10.1

Messaggio di avviso dalla traccia dello stack:

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)

Dopo aver cercato i problemi di github, la documentazione e aver creato simili perdite di memoria dell'emettitore di eventi, questo problema è stato osservato a causa del modulo node-apn utilizzato per la notifica push di iOS.

Questo l'ha risolto:

È necessario creare un solo provider per processo per ogni coppia certificato / chiave posseduta. Non è necessario creare un nuovo provider per ciascuna notifica. Se invii notifiche solo a un'app, non è necessario più di un provider.

Se crei costantemente istanze di provider nella tua app, assicurati di chiamare Provider.shutdown () quando hai finito con ciascun provider per rilasciare le sue risorse e memoria.

Stavo creando l'oggetto provider ogni volta che la notifica veniva inviata e mi aspettavo che il gc lo cancellasse.


2

Nel mio caso, era quello child.stderr.pipe(process.stderr)che veniva chiamato quando stavo iniziando 10 (circa) istanze del bambino. Quindi, qualsiasi cosa, che porta ad associare un gestore di eventi allo stesso oggetto EventEmitter in un LOOP, fa sì che nodejs lanci questo errore.


2

A volte questi avvisi si verificano quando non è qualcosa che abbiamo fatto, ma qualcosa che abbiamo dimenticato di fare!

Ho riscontrato questo avviso quando ho installato il pacchetto dotenv con npm, ma sono stato interrotto prima di andare in giro per aggiungere l'istruzione request ('dotenv'). Load () all'inizio della mia app. Quando sono tornato al progetto, ho iniziato a ricevere gli avvisi "Possibile perdita di memoria EventEmitter rilevata".

Pensavo che il problema fosse dovuto a qualcosa che avevo fatto, non a qualcosa che non avevo fatto!

Quando ho scoperto la mia svista e ho aggiunto la dichiarazione obbligatoria, l'avviso di perdita di memoria è stato cancellato.


2

Preferisco dare la caccia e risolvere i problemi invece di sopprimere i registri quando possibile. Dopo un paio di giorni di osservazione di questo problema nella mia app, mi sono reso conto che stavo impostando gli ascoltatori sul req.socketmiddleware Express per rilevare errori socket io che continuavano ad apparire. Ad un certo punto, ho imparato che non era necessario, ma ho comunque tenuto gli ascoltatori in giro. Li ho appena rimossi e l'errore che stai riscontrando è andato via. Ho verificato che era la causa eseguendo richieste sul mio server con e senza il seguente 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();
    }

La rimozione di quel middleware ha interrotto l'avviso visualizzato. Mi guarderei intorno al tuo codice e proverei a trovare ovunque tu stia creando dei listener che non ti servono.


1

Avevo lo stesso problema. e il problema è stato causato perché stavo ascoltando la porta 8080, su 2 ascoltatori.

setMaxListeners() funziona bene, ma non lo consiglierei.

il modo corretto è, controllare il codice per ulteriori ascoltatori, rimuovere l'ascoltatore o modificare il numero di porta su cui si sta ascoltando, questo ha risolto il mio problema.


1

L'ho avuto fino ad oggi quando inizio grunt watch. Finalmente risolto da

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

Il fastidioso messaggio è sparito.


1

Devi cancellare tutti i listener prima di crearne di nuovi usando:

Client / Server

socket.removeAllListeners(); 

Supponendo che socket sia il tuo socket client / o il socket del server creato.

Puoi anche iscriverti a listener di eventi specifici, ad esempio rimuovendo l' connectascoltatore in questo modo:

this.socket.removeAllListeners("connect");

0

Hai detto che stai usando process.on('uncaughtException', callback);
Dove stai eseguendo questa affermazione? È nel callback passato a http.createServer?
In caso affermativo, una copia diversa dello stesso callback verrà allegata all'evento uncaughtException ad ogni nuova richiesta, poiché function (req, res) { ... }viene eseguita ogni volta che arriva una nuova richiesta e così anche l'istruzione process.on('uncaughtException', callback);
Nota che l' oggetto processo è globale per tutte le tue richieste e l'aggiunta di listener al suo evento ogni volta che arriva una nuova richiesta non avrà alcun senso. Potresti non voler questo tipo di comportamento.
Nel caso in cui si desideri allegare un nuovo listener per ogni nuova richiesta, è necessario rimuovere tutti i listener precedenti collegati all'evento poiché non sarebbero più necessari utilizzando:
process.removeAllListeners('uncaughtException');


0

La correzione del nostro team per questo è stata la rimozione di un percorso di registro dal nostro .npmrc. Avevamo due alias di percorso nel file rc e uno puntava a un'istanza Artifactory che era stata deprecata.

L'errore non aveva nulla a che fare con il codice effettivo della nostra app ma tutto con il nostro ambiente di sviluppo.


0

Stavo affrontando lo stesso problema, ma ho gestito con successo con Async wait.
Si prega di verificare se aiuta.

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

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


0

Grazie a RLaaa per avermi dato un'idea su come risolvere il vero problema / causa principale dell'avviso. Bene nel mio caso era il codice buggy MySQL.

Fornendo che hai scritto una Promessa con il codice all'interno in questo modo:

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

Si noti che c'è un conn.on('error')ascoltatore nel codice. Quel codice che aggiunge letteralmente il listener più e più volte dipende da quante volte chiamate la query. Nel frattempo if(err) reject(err)fa la stessa cosa.

Quindi ho rimosso l' conn.on('error')ascoltatore e voilà ... risolto! Spero che questo ti aiuti.


-4

Inseriscilo nella prima riga del tuo server.js (o qualunque cosa contenga la tua app Node.js principale):

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

e l'errore scompare :)


Mi hai dato l'idea di metterlo in un file principale e ha funzionato. Lo stavo solo mettendo in un posto sbagliato. Grazie!
sklimkovitch,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.