web-dev-qa-db-fra.com

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

Je reçois un 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 un code comme celui-ci dans server.js:

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

Comment régler ceci ?

187
Riz

Ceci est expliqué dans le manuel: http://nodejs.org/docs/latest/api/events.html#events_emitter_setmaxlisteners_n

Quelle version de Node est-ce? Quel autre code avez-vous? Ce n'est pas un comportement normal.

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

Voir aussi: node.js - request - Comment “emitter.setMaxListeners ()”?

87
Corey Richardson

Je tiens à souligner ici que cet avertissement existe pour une raison et qu'il est fort probable que la bonne solution soit pas augmenter la limite mais comprendre pourquoi vous ajoutez autant d'auditeurs à la même chose un événement. N'augmentez la limite que si vous savez pourquoi tant d'auditeurs sont ajoutés et si vous êtes certain que c'est ce que vous voulez vraiment.

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

167
voltrevo

Par défaut, un maximum de 10 auditeurs peuvent être enregistrés pour un seul é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 cette 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 soyez prudent:

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

ADD: Depuis le noeud 0.11, ce code permet également de modifier la limite par défaut:

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

La réponse acceptée fournit la sémantique sur la manière d’augmenter la limite, mais comme @voltrevo l’a signalé, cet avertissement existe pour une raison et que 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 manière correcte d’ajouter l’auditeur:

//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 changer les maxListeners (ce qui est expliqué dans d'autres réponses)

55
RLaaa

Remplacez .on() par once(). L'utilisation de once() supprime les écouteurs d'événements lorsque l'événement est géré par la même fonction. Source: http://nodeguide.com/beginner.html#using-eventemitters

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

Cela a à voir avec restler 0,10 se comportant mal avec noeud. 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 cette mise à jour, c'est pourquoi vous devez vous référer à la tête de git.

19
Davis Dulin

Je reçois aussi cet avertissement lors de l’installation d’aglio sur mon mac osx.

J'utilise cmd le réparer.

Sudo npm install -g npm@next

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

3
Legolas Bloom

Je préfère traquer et résoudre les problèmes plutôt que de supprimer les journaux chaque fois que cela est possible. Après avoir observé ce problème dans mon application pendant quelques jours, je me suis rendu compte que je plaçais des auditeurs sur le req.socket dans un middleware Express pour intercepter les erreurs de socket io qui ne cessaient de surgir. À un moment donné, j'ai appris que ce n'était pas nécessaire, mais j'ai quand même gardé les auditeurs autour. Je viens de les supprimer et l'erreur que vous rencontrez est partie. 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 arrêté l'avertissement que vous voyez. Je regarderais autour de votre code et essayerais de trouver n'importe quel endroit où vous pourriez installer des écouteurs dont vous n'avez pas besoin.

2
lwdthe1

Dans mon cas, c’était child.stderr.pipe(process.stderr) qui était appelé lorsque j’ai initié 10 instances (ou plus) de l’enfant. Donc, quoi que ce soit qui amène à attacher un gestionnaire d’événements au même objet EventEmitter dans une boucle, pousse nodejs à lancer cette erreur.

2
Vikas Gautam

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 paquet dotenv avec npm, mais j'ai été interrompu avant l'ajout de l'instruction require ('dotenv'). Load () au début de mon application. Lorsque je suis revenu dans le projet, j'ai commencé à recevoir les avertissements "Fuite de mémoire possible EventEmitter 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é l'instruction require, l'avertissement de fuite de mémoire s'est effacé.

2
Motate

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

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

Le message agaçant est parti.

1
Ariful Haque

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.

pour corriger le problème, vérifiez si votre code contient des écouteurs supplémentaires, supprimez l’auditeur ou modifiez le numéro de port sur lequel vous écoutez. Cela a résolu mon problème.

1
Noman Abid

La solution de notre équipe à cet égard consistait à supprimer un chemin de registre de notre .npmrc. Nous avions deux alias de chemin dans le fichier rc, et 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.

0
RossO

Version du nœud: v11.10.1

Message d'avertissement de la trace de la 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é des problèmes avec github, consulté de la documentation et créé des fuites de mémoire similaires dans l'émetteur d'événements, 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. Il n'est pas nécessaire 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, veillez à 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 le supprime.

0
Sandeep PC

Vous avez dit que vous utilisiez process.on('uncaughtException', callback);
Où exécutez-vous cette déclaration? Est-ce que le rappel est passé à http.createServer?
Si oui, une copie différente du même rappel sera jointe à l'événement ncaughtException à chaque nouvelle demande, car function (req, res) { ... } est exécuté à chaque fois qu'une nouvelle demande arrive, ainsi que l'instruction process.on('uncaughtException', callback);.
Notez que l’objet de processus est global pour toutes vos demandes et que l’ajout d’écouteurs à son événement chaque fois qu’une nouvelle demande arrive ne fera aucune sens. Vous pourriez ne pas vouloir ce genre de comportement.
Si 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 à l'aide de:
process.removeAllListeners('uncaughtException');

0
Monish Chhadwa

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

Client/Serveur

socket.removeAllListeners(); 

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

Vous pouvez également vous abonner à des écouteurs d'événements spécifiques, par exemple en supprimant l'auditeur connect comme ceci:

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