Mon code JavaSript crée une liste d'éléments LI
. Lorsque je mets à jour la liste, l'utilisation de la mémoire augmente et ne diminue jamais. J'ai testé dans sIEve et cela montre que le navigateur conserve tous les éléments qui étaient censés être supprimés par $.remove()
ou $.empty
Commandes jQuery.
Que dois-je faire pour supprimer les nœuds DOM sans fuite de mémoire?
Voir mon autre question pour le code spécifique.
Le DOM conserve tous les nœuds DOM, même s'ils ont été supprimés de l'arborescence DOM lui-même, la seule façon de supprimer ces nœuds est de faire un rafraîchissement de page (si vous mettez la liste dans un iframe, le rafraîchissement ne sera pas aussi perceptible)
Sinon, vous pourriez attendre que le problème s'aggrave suffisamment pour que le ramasse-miettes des navigateurs soit forcé d'agir (en parlant ici de centaines de mégaoctets de nœuds inutilisés)
La meilleure pratique consiste à réutiliser les nœuds.
EDIT: Essayez ceci:
var garbageBin;
window.onload = function ()
{
if (typeof(garbageBin) === 'undefined')
{
//Here we are creating a 'garbage bin' object to temporarily
//store elements that are to be discarded
garbageBin = document.createElement('div');
garbageBin.style.display = 'none'; //Make sure it is not displayed
document.body.appendChild(garbageBin);
}
function discardElement(element)
{
//The way this works is due to the phenomenon whereby child nodes
//of an object with it's innerHTML emptied are removed from memory
//Move the element to the garbage bin element
garbageBin.appendChild(element);
//Empty the garbage bin
garbageBin.innerHTML = "";
}
}
Pour l'utiliser dans votre contexte, vous le feriez comme ceci:
discardElement(this);
C'est plus une [~ # ~] fyi [~ # ~] qu'une réponse réelle, mais elle est aussi très intéressante.
À partir de la spécification du noyau DOM W3C (http://www.w3.org/TR/DOM-Level-2-Core/core.html):
Les API Core DOM sont conçues pour être compatibles avec un large éventail de langages, y compris les langages de script utilisateur général et les langages les plus difficiles utilisés principalement par les programmeurs professionnels. Ainsi, les API DOM doivent fonctionner dans une variété de philosophies de gestion de la mémoire, des liaisons de langage qui n'exposent pas du tout la gestion de la mémoire à l'utilisateur, en passant par celles (notamment Java) qui fournissent des constructeurs explicites mais fournissent un mécanisme de collecte automatique des ordures pour automatiquement récupérer la mémoire inutilisée, à ceux (en particulier C/C++) qui nécessitent généralement que le programmeur alloue explicitement la mémoire des objets, suit où elle est utilisée et la libère explicitement pour une réutilisation. Pour garantir une API cohérente sur ces plates-formes, le DOM ne résout pas du tout les problèmes de gestion de la mémoire, mais les laisse à la place pour l'implémentation. Aucune des liaisons de langage explicites définies par l'API DOM (pour ECMAScript et Java) ne nécessite de méthodes de gestion de la mémoire, mais les liaisons DOM pour d'autres langues (en particulier C ou C++) peuvent nécessiter une telle prise en charge. Ces extensions seront la responsabilité de ceux qui adaptent l'API DOM à une langue spécifique, et non le groupe de travail DOM.
En d'autres termes: la gestion de la mémoire est laissée à l'implémentation de la spécification DOM dans différents langages. Vous devriez regarder dans la documentation de l'implémentation DOM en javascript pour trouver une méthode pour supprimer un objet DOM de la mémoire, ce qui n'est pas un hack. (Il y a cependant très peu d'informations sur le site du MDC à ce sujet.)
Comme une note sur jQuery#remove
et jQuery#empty
: d'après ce que je peux dire, aucune de ces méthodes ne fait autre chose que la suppression de Object
s du DOM node
s ou la suppression du DOM node
s du document
. Ils ne font que supprimer Cela ne signifie bien sûr pas qu'il n'y a pas de mémoire allouée à ces objets (même s'ils ne sont plus dans le document
).
Edit: Le passage ci-dessus était superflu car évidemment jQuery ne peut pas faire de merveilles et contourner l'implémentation DOM du navigateur utilisé.
Avez-vous supprimé des écouteurs d'événements? Cela peut provoquer des fuites de mémoire .
Le code ci-dessous ne fuit pas sur mon IE7 et d'autres navigateurs:
<html>
<head></head>
<body>
<a href="javascript:" onclick="addRemove(this)">add</a>
<ul></ul>
<script>
function addRemove(a) {
var ul = document.getElementsByTagName('UL')[0],
li, i = 20000;
if (a.innerHTML === 'add') {
while (i--) {
li = document.createElement('LI');
ul.appendChild(li);
li.innerHTML = i;
li.onclick = function() {
alert(this.innerHTML);
};
}
a.innerHTML = 'remove';
} else {
while (ul.firstChild) {
ul.removeChild(ul.firstChild);
}
a.innerHTML = 'add';
}
}
</script>
</body>
</html>
Peut-être que vous pouvez essayer de repérer certaines différences avec votre code.
Je sais que IE fuit beaucoup moins lorsque vous insérez d'abord le nœud dans le DOM avant de lui faire quoi que ce soit, par exemple: y attacher des événements ou remplir son innerHTML
propriété.
Si vous devez "post-corriger" une fuite et devez le faire sans réécrire tout votre code pour prendre en compte les fermetures, les références circulaires, etc., utilisez la méthode de purge Douglas Crockfords avant de supprimer:
http://javascript.crockford.com/memory/leak.html
Ou utilisez cette solution de contournement de fermeture: