web-dev-qa-db-fra.com

Comment éviter les fuites de mémoire dans node.js?

Nous savons que node.js nous donne une grande puissance mais avec une grande puissance vient une grande responsabilité.

Pour autant que je sache, le moteur V8 ne fait aucune collecte de déchets. Quelles sont donc les erreurs les plus courantes que nous devons éviter pour garantir qu'aucune mémoire ne fuit de mon serveur de nœud.

EDIT: Désolé pour mon ignorance, V8 a un puissant récupérateur de déchets.

45
neebz

Pour autant que je sache, le moteur V8 ne fait aucune collecte de déchets.

V8 a un récupérateur de déchets puissant et intelligent en construction.

Votre principal problème n'est pas de comprendre comment les fermetures conservent une référence à la portée et au contexte des fonctions externes. Cela signifie qu'il existe différentes façons de créer des références circulaires ou de créer des variables qui ne font pas un nettoyage.

C'est parce que votre code est ambigüe et le compilateur ne peut pas dire s'il est sûr pour le ramasser les ordures.

Un moyen de forcer le GC à récupérer des données consiste à annuler vos variables.

function(foo, cb) {
    var bigObject = new BigObject();
    doFoo(foo).on("change", function(e) {
         if (e.type === bigObject.type) {
              cb();
              // bigObject = null;
         }
    });
}

Comment la v8 sait-elle s'il est sûr de nettoyer le gros objet lorsqu'il se trouve dans un gestionnaire d'événements? Ce n'est pas le cas, vous devez donc lui dire qu'il n'est plus utilisé en définissant la variable sur null.

Divers articles à lire:

65
Raynos

Je voulais me convaincre de la réponse acceptée, en particulier:

ne pas comprendre comment les fermetures maintiennent une référence à la portée et au contexte des fonctions externes.

J'ai donc écrit le code suivant pour montrer comment les variables peuvent ne pas être nettoyées, ce que les gens peuvent trouver intéressant.

Si vous avez watch -n 0.2 'ps -o rss $(pgrep node)' en cours d'exécution dans un autre terminal, vous pouvez voir la fuite se produire. Notez comment commenter dans le buffer = nullo en utilisant nextTick permettra au processus de se terminer:

(function () {
    "use strict";

    var fs = require('fs'),
        iterations = 0,

        work = function (callback) {
            var buffer = '',
                i;

            console.log('Work ' + iterations);

            for (i = 0; i < 50; i += 1) {
                buffer += fs.readFileSync('/usr/share/dict/words');
            }

            iterations += 1;
            if (iterations < 100) {
                // buffer = null;

                // process.nextTick(function () {
                    work(callback);
                // });
            } else {
                callback();
            }
        };

    work(function () {
        console.log('Done');
    });

}());
24
dukedave

collecte active des ordures avec:

node --expose-gc test.js

et utiliser avec:

global.gc();

Happy Coding :)

9
kazelsama