possible fuite de mémoire EventEmitter détectée

231

Je reçois l'avertissement suivant:

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

J'ai écrit du code comme celui-ci dans server.js:

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

Comment régler ceci ?

Riz
la source
46
Utilisez process.on('warning', e => console.warn(e.stack));pour déboguer l'avertissement. Ne pas utiliser process.setMaxListeners(0);car l'avertissement est là pour une raison quelconque.
Shwetabh Shekhar
Je vous remercie. instruction très utile.
Abdullah Al Farooq
cette erreur m'arrive yarn install. où puis-je mettre cette ligne pour ajouter une trace de pile?
Sonic Soul

Réponses:

94

Ceci est expliqué dans la documentation du nœud eventEmitter

De quelle version de Node s'agit-il? Quel autre code avez-vous? Ce n'est pas un comportement normal.

Bref, c'est: process.setMaxListeners(0);

Voir aussi: node.js - request - Comment «emitter.setMaxListeners ()»?

Corey Richardson
la source
1
v0.6.11 ... J'ai tout fait, mais l'avertissement est toujours là. :(
Riz
5
J'utiliseprocess.on('uncaughtException', callback);
Riz
9
process.setMaxListeners(0); // OMG, its so simple... :D
Riz
11
Je ne supprimerais pas la limite d'écoute maximale. Vous n'obtiendrez pas d'avertissement, mais vous obtiendrez des fuites de mémoire.
15
Comment cette réponse a-t-elle obtenu tous ces votes et a-t-elle été choisie comme bonne réponse? même si cela devrait fonctionner, mais c'est complètement faux !!
ProllyGeek
205

Je voudrais souligner ici que cet avertissement est là pour une raison et il y a de fortes chances que la bonne solution n'augmente pas la limite mais trouve pourquoi vous ajoutez autant d'auditeurs au même événement. N'augmentez la limite que si vous savez pourquoi tant d'auditeurs sont ajoutés et que vous êtes convaincu que c'est ce que vous voulez vraiment.

J'ai trouvé cette page parce que j'ai reçu cet avertissement et dans mon cas, il y avait un bogue dans un code que j'utilisais qui transformait l'objet global en un EventEmitter! Je déconseillerais certainement d'augmenter la limite à l'échelle mondiale parce que vous ne voulez pas que ces choses passent inaperçues.

voltrevo
la source
14
+1. D'accord. L'avertissement indique un état de fuite potentiel et l'augmentation inconsidérée des maxListeners ne résoudra pas nécessairement le problème. jongleberry.com/understanding-possible-eventemitter-leaks.html
Jeremiah Adams
3
Comment pouvez-vous déboguer "Avertissement: fuite de mémoire EventEmitter possible détectée. 11 écouteurs d'erreur ajoutés. Utilisez emitter.setMaxListeners () pour augmenter la limite". Que devons-nous rechercher?
Phil
2
Mais il n'y a aucune trace de pile et aucun code avec ce message d'erreur. Je reçois les majuscules W et P sur "Avertissement" et "Possible", donc je pense que ce pourrait être une erreur différente. J'ai besoin de plus d'un événement écouté, mais je n'appelle .on qu'une seule fois dans tous les cas, donc je ne sais pas quel est le problème.
Phil
2
@ Phil_1984_ Avez-vous trouvé une solution? sinon cela semble fonctionner - stackoverflow.com/questions/38482223/…
Yoni Jah
3
Pour info, le lien du premier commentaire (jongleberry.com) est hors ligne. Voici la version archivée: web.archive.org/web/20180315203155/http://www.jongleberry.com/…
Jeff Ward
76

Par défaut, un maximum de 10 auditeurs peuvent être enregistrés pour un même événement.

Si c'est votre code, vous pouvez spécifier maxListeners via:

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

Mais si ce n'est pas votre code, vous pouvez utiliser l'astuce pour augmenter globalement la limite par défaut:

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

Bien sûr, vous pouvez désactiver les limites mais faites attention:

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

BTW. Le code devrait être au tout début de l'application.

AJOUTER: Depuis le noeud 0.11, ce code fonctionne également pour modifier la limite par défaut:

require('events').EventEmitter.defaultMaxListeners = 0
zag2art
la source
5
C'était la seule solution qui fonctionnait pour moi dans le Node 5.6.0. Merci beaucoup!
Andrew Faulkner
J'utilise la version 8 de node native de react. *. *. Ça n'a pas marché pour moi.
Thomas Valadez
le mien était require («événements»). EventEmitter.defaultMaxListeners = Infinity;
Karl Anthony Baluyot
73

La réponse acceptée fournit la sémantique sur la façon d'augmenter la limite, mais comme @voltrevo l'a souligné, l'avertissement est là pour une raison et votre code a probablement un bogue.

Considérez le code buggy suivant:

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

Observez maintenant la bonne façon d'ajouter l'écouteur:

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

Recherchez des problèmes similaires dans votre code avant de modifier les maxListeners (ce qui est expliqué dans d'autres réponses)

Rayee Roded
la source
13
cette réponse doit être acceptée car elle montre la raison réelle de l'avertissement et comment le résoudre, +1
Ganesh Karewad
Ceci est la bonne réponse! Je pense honnêtement que l'avertissement maxListener apparaît principalement à cause de certains codes buggy. Dans mon cas, c'était le code mysql. Je vais essayer de répondre simplement pour clarifier cela.
Adrian
25

Remplacez .on()par once(). L'utilisation once()supprime les écouteurs d'événements lorsque l'événement est géré par la même fonction.

Si cela ne le résout pas, réinstallez restler avec ceci dans votre package.json "restler": "git: //github.com/danwrong/restler.git#9d455ff14c57ddbe263dbbcd0289d76413bfe07d"

Cela a à voir avec le restler 0.10 qui se comporte mal avec le nœud. vous pouvez voir le problème fermé sur git ici: https://github.com/danwrong/restler/issues/112 Cependant, npm n'a pas encore mis à jour cela, c'est pourquoi vous devez vous référer à la tête de git.

Davis Dulin
la source
cela corrige cette erreur sur mon code en utilisant le framework Puppeterr
C Alonso C Ortega
5

J'obtiens également cet avertissement lorsque j'installe aglio sur mon mac osx.

J'utilise cmd pour le réparer.

sudo npm install -g npm@next

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

Legolas Bloom
la source
4

Version du nœud: v11.10.1

Message d'avertissement de trace de pile:

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)

Après avoir recherché les problèmes de github, la documentation et créé des fuites de mémoire d'émetteur d'événements similaires, ce problème a été observé en raison du module node-apn utilisé pour la notification push iOS.

Cela l'a résolu:

Vous ne devez créer qu'un seul fournisseur par processus pour chaque paire de certificats / clés que vous possédez. Vous n'avez pas besoin de créer un nouveau fournisseur pour chaque notification. Si vous n'envoyez des notifications qu'à une seule application, il n'est pas nécessaire d'avoir plus d'un fournisseur.

Si vous créez constamment des instances de fournisseur dans votre application, assurez-vous d'appeler Provider.shutdown () lorsque vous avez terminé avec chaque fournisseur pour libérer ses ressources et sa mémoire.

Je créais un objet fournisseur à chaque fois que la notification était envoyée et je m'attendais à ce que le GC l'efface.

Sandeep PC
la source
2

Dans mon cas, c'était child.stderr.pipe(process.stderr)ce qui était appelé lorsque j'initiais 10 (ou presque) cas de l'enfant. Donc, tout ce qui conduit à attacher un gestionnaire d'événements au même objet EventEmitter dans une boucle, fait que nodejs renvoie cette erreur.

Vikas Gautam
la source
2

Parfois, ces avertissements se produisent lorsque ce n'est pas quelque chose que nous avons fait, mais quelque chose que nous avons oublié de faire!

J'ai rencontré cet avertissement lorsque j'ai installé le package dotenv avec npm, mais j'ai été interrompu avant de pouvoir ajouter l'instruction require ('dotenv'). Load () au début de mon application. Lorsque je suis retourné au projet, j'ai commencé à recevoir les avertissements "Fuite de mémoire EventEmitter possible détectée".

J'ai supposé que le problème venait de quelque chose que j'avais fait, pas de quelque chose que je n'avais pas fait!

Une fois que j'ai découvert mon oubli et ajouté la déclaration require, l'avertissement de fuite de mémoire s'est effacé.

Motate
la source
2

Je préfère traquer et résoudre les problèmes au lieu de supprimer les journaux chaque fois que possible. Après quelques jours d'observation de ce problème dans mon application, j'ai réalisé que je configurais les écouteurs sur req.socketun middleware Express pour détecter les erreurs de socket io qui ne cessaient d'apparaître. À un moment donné, j'ai appris que ce n'était pas nécessaire, mais j'ai quand même gardé les auditeurs. Je viens de les supprimer et l'erreur que vous rencontrez a disparu. J'ai vérifié que c'était la cause en exécutant des requêtes sur mon serveur avec et sans le middleware suivant:

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 suppression de ce middleware a stoppé l'avertissement que vous voyez. Je regarderais autour de votre code et essayerais de trouver n'importe où vous pouvez configurer des écouteurs dont vous n'avez pas besoin.

lwdthe1
la source
1

j'avais le même problème. et le problème a été causé parce que j'écoutais le port 8080, sur 2 auditeurs.

setMaxListeners() fonctionne bien, mais je ne le recommanderais pas.

la bonne façon est de vérifier votre code pour des écouteurs supplémentaires, de supprimer l'écouteur ou de changer le numéro de port sur lequel vous écoutez, cela a résolu mon problème.

Noman Abid
la source
1

J'avais ça jusqu'à aujourd'hui quand je commence grunt watch. Enfin résolu par

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

Le message ennuyeux a disparu.

Ariful Haque
la source
1

Vous devez effacer tous les écouteurs avant d'en créer de nouveaux en utilisant:

Serveur client

socket.removeAllListeners(); 

En supposant que socket est votre socket client / ou socket serveur créé.

Vous pouvez également vous abonner à partir d'écouteurs d'événements spécifiques, comme par exemple supprimer l' connectauditeur comme ceci:

this.socket.removeAllListeners("connect");
ProllyGeek
la source
0

Vous avez dit que vous utilisez process.on('uncaughtException', callback);
Où exécutez-vous cette instruction? Est-ce dans le rappel passé à http.createServer?
Si oui, une copie différente du même rappel sera attachée à l' événement uncaughtException à chaque nouvelle demande, car l'objet function (req, res) { ... }est exécuté à chaque fois qu'une nouvelle demande arrive, de même que l'instruction. process.on('uncaughtException', callback);
Notez que l' objet de processus est global pour toutes vos demandes et l'ajout d'écouteurs à son événement chaque fois qu'une nouvelle demande arrive n'a aucun sens. Vous pourriez ne pas vouloir ce genre de comportement.
Dans le cas où vous souhaitez attacher un nouvel écouteur pour chaque nouvelle demande, vous devez supprimer tous les écouteurs précédents attachés à l'événement car ils ne seraient plus nécessaires en utilisant:
process.removeAllListeners('uncaughtException');

Monish Chhadwa
la source
0

Le correctif de notre équipe pour cela supprimait un chemin de registre de notre .npmrc. Nous avions deux alias de chemin dans le fichier rc, et l'un pointait vers une instance Artifactory qui était obsolète.

L'erreur n'avait rien à voir avec le code réel de notre application, mais tout à voir avec notre environnement de développement.

RossO
la source
0

J'étais confronté au même problème, mais j'ai réussi à gérer avec async.
Veuillez vérifier si cela aide.

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

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

Vivek Mehta
la source
0

Merci à RLaaa de m'avoir donné une idée de la façon de résoudre le vrai problème / la cause profonde de l'avertissement. Eh bien dans mon cas, c'était du code buggy MySQL.

À condition que vous ayez écrit une promesse avec du code à l'intérieur comme ceci:

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

Notez qu'il y a un conn.on('error')écouteur dans le code. Ce code ajoutant littéralement l'écouteur encore et encore dépend du nombre de fois que vous appelez la requête. En attendant, if(err) reject(err)fait la même chose.

J'ai donc supprimé l' conn.on('error')auditeur et le tour est joué ... résolu! J'espère que cela vous aidera.

Adrian
la source
-4

Mettez ceci dans la première ligne de votre server.js (ou tout ce qui contient votre application Node.js principale):

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

et l'erreur disparaît :)

Sébastien
la source
Vous m'avez donné une idée pour le mettre dans un fichier principal, et cela a fonctionné. Je le mettais juste au mauvais endroit. Merci!
sklimkovitch