44 votes

Modèles de fuite de mémoire jQuery et leurs causes

Quels sont certains des problèmes ou des modèles de codage en jQuery qui conduisent à des fuites de mémoire?


J'ai vu un certain nombre de questions liées à l'ajax() appel ou jsonp ou DOM retrait sur StackOverflow. La plupart des jQuery fuite de mémoire les questions portent principalement sur des questions spécifiques ou des navigateurs et il serait bien d'avoir une liste de la norme de fuite de mémoire de modèles dans jQuery.

Voici quelques questions connexes AINSI:

Ressources sur le web:

29voto

tofarr Points 2069

Ce que je comprends, la gestion de la mémoire en javascript est accompli par comptage de référence - tout une référence à un objet existe toujours, il ne sera pas libéré. Cela signifie que la création d'une fuite de mémoire dans une page unique application est trivial, et peut aller jusqu'à ceux de l'utilisation à venir de java arrière-plan. Ce n'est pas spécifique à JQuery. Prenez le code suivant par exemple:

function MyObject = function(){
   var _this = this;
   this.count = 0;
   this.getAndIncrement = function(){
       _this.count++;
       return _this.count;
   }
}

for(var i = 0; i < 10000; i++){
    var obj = new MyObject();
    obj.getAndIncrement();
}

Il a un aspect normal jusqu'à ce que vous regardez à l'utilisation de la mémoire. Les Instances de MyObject ne sont jamais libérées pendant que la page est active, en raison de la "_ce" pointeur (augmentation de la valeur max de j'voir plus de façon spectaculaire.). (Dans les anciennes versions d'IE, ils n'ont jamais été libéré jusqu'à ce que le programme s'arrête.) Depuis les objets javascript peut être partagée entre les images (je ne recommande pas d'essayer cela comme il est très capricieux.), il y a des cas où, même dans un navigateur moderne des objets javascript peut traîner beaucoup plus que ce qu'ils sont censés le faire.

Dans le contexte de jquery, les références sont souvent stockées pour économiser les frais généraux des dom de la recherche - par exemple:

function run(){
    var domObjects = $(".myClass");
    domObjects.click(function(){
        domObjects.addClass(".myOtherClass");
    });
}

Ce code tiendra à domObject (et tout son contenu) pour toujours, à cause de la référence à la fonction de rappel.

Si les auteurs de jquery ont manqué cas comme celui-là à l'interne, puis la bibliothèque elle-même est une fuite, mais le plus souvent, c'est le code du client.

Le deuxième exemple peut être fixe explicitement de compensation du pointeur lorsqu'il n'est plus nécessaire:

function run(){
    var domObjects = $(".myClass");
    domObjects.click(function(){
        if(domObjects){
            domObjects.addClass(".myOtherClass");
            domObjects = null;
        }
    });
}

ou de faire la recherche de nouveau:

function run(){
    $(".myClass").click(function(){
        $(".myClass").addClass(".myOtherClass");
    });
}

Une bonne règle de base est d'être prudent lorsque vous définissez vos fonctions de rappel, et d'éviter trop de nidification où c'est possible.

Edit: Comme l'a souligné dans les commentaires par Erik, vous pouvez également utiliser ce pointeur pour éviter la unnescessary dom recherche:

function run(){
    $(".myClass").click(function(){
        $(this).addClass(".myOtherClass");
    });
}

16voto

Dave Methvin Points 1153

Je vais contribuer un anti-modèle, qui est le "milieu de la chaîne de référence de la fuite.

L'un de jQuery points forts est sa le chaînage de l'API, qui vous permet de continuer à changer, de filtre et de manipuler les éléments: $(".message").addClass("unread").find(".author").addClass("noob"); À la fin de cette chaîne vous avez un objet jQuery avec tous les ".message .auteur des" éléments, mais que l' objet renvoie à l'objet et à l'original ".message" éléments. Vous pouvez obtenir par l'intermédiaire de l' .end() méthode et de faire quelque chose pour eux: $(".message") .find(".author") .addClass("prolific") .end() .addClass("unread"); Maintenant, quand utilisé de cette façon, il n'y a pas de problèmes avec des fuites. Toutefois, si vous attribuez le résultat d'une chaîne à une variable qui a une longue durée de vie, l'arrière-références antérieures ensembles de rester autour et ne peut pas être nettoyée jusqu'à ce que la variable est hors de portée. Si cette variable est globale, les références ne vont jamais hors de portée.

Ainsi, par exemple, disons que vous avez lu sur certains 2008 post de blog qui $("a").find("b") a été "plus efficace" que $("a b") (même si sa ne mérite pas de même de penser à un tel micro-optimisation). Vous décidez que vous avez besoin d'une page à l'échelle mondiale afin de tenir une liste des auteurs afin de vous faire ceci: authors = $(".message").find(".author"); Maintenant, vous avez un objet jQuery avec la liste des auteurs, mais il renvoie également à un objet jQuery qui est la liste complète des messages. Vous n'aurez probablement jamais utiliser ou même de savoir qu'il est là, et il prend de la mémoire.

Notez que les fuites peuvent se produire uniquement avec les méthodes de sélectionner de nouveaux éléments à partir d'un jeu existant, comme .find, .filter, .children etc. Les docs d'indiquer qu'un nouveau jeu est retournée. Simplement à l'aide d'un chaînage API ne pas provoquer une fuite si la chaîne est simple non-méthodes de filtrage comme .css, donc c'est ok: authors = $(".message .author").addClass("prolific");

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X