307 votes

Qu'est-ce que le garbage collection de JavaScript ?

Qu'est-ce que le garbage collection JavaScript ? Qu'est-ce qu'il est important pour un programmeur web de comprendre sur le garbage collection JavaScript, afin d'écrire un meilleur code ?

3 votes

1 votes

198voto

Noldorin Points 67794

Eric Lippert a écrit un article de blog détaillé sur ce sujet il y a un certain temps (en le comparant en outre à VBScript ). Plus précisément, il a écrit sur JScript qui est la propre mise en œuvre de l'ECMAScript par Microsoft, bien que très similaire à JavaScript. J'imagine que vous pouvez supposer que la grande majorité du comportement sera le même pour le moteur JavaScript d'Internet Explorer. Bien sûr, la mise en œuvre variera d'un navigateur à l'autre, mais je pense qu'il est possible de prendre un certain nombre de principes communs et de les appliquer à d'autres navigateurs.

Citation de cette page :

JScript utilise un collecteur de déchets non générationnel non générationnel, de type mark-and-sweep. Il fonctionne comme suit :

  • Chaque variable qui est "in scope" est appelée un "scavenger". Un scavenger peut faire référence à un nombre, un objet, une chaîne de caractères, etc. Nous maintenons une liste de scavengers -- les variables sont déplacées sur la liste des scavengers lorsqu'elles entrent lorsqu'elles entrent dans le champ d'application et lorsqu'elles sortent du champ d'application.

  • De temps en temps, le ramasseur d'ordures s'exécute. D'abord, il met une "marque " sur chaque objet, variable, chaîne, etc - toute la mémoire suivie par le GC. (JScript utilise la structure de données VARIANT en interne et il y a beaucoup de bits de nombreux bits supplémentaires inutilisés dans inutilisés dans cette structure, nous nous contentons donc d'en définir un l'un d'eux).

  • Deuxièmement, il clarifie la marque sur les charognards et la fermeture transitive des références aux charognards. Donc si un objet charognard fait référence à un un objet non charognard, nous effaçons les bits bits sur le non-violeur, et sur tout ce à quoi il fait référence. (Je suis j'utilise le mot "fermeture" dans un sens différent que dans mon précédent post précédent).

  • À ce stade, nous savons que toute la mémoire encore marquée est de la mémoire allouée qui ne peut être atteinte par aucun chemin chemin à partir d'une quelconque variable du champ d'application. Tous les de ces objets ont pour instruction de de se détruire, ce qui détruit toute référence circulaire.

L'objectif principal du ramassage des déchets est de permettre au programmeur pas de se soucier de la gestion de la mémoire des objets qu'ils créent et utilisent, même si, bien entendu, on ne peut pas toujours l'éviter - il est toujours bénéfique d'avoir au moins une idée approximative du fonctionnement du ramassage des déchets.

Il y a quelques points particuliers dont il faut être conscient. Le site des développeurs Apple a quelques lignes directrices sur la question. Il y en a deux importantes :

  • Utilisez des instructions de suppression. Chaque fois que vous créez un objet à l'aide d'une instruction new, associez-la à une instruction delete. Cela garantit que toute la mémoire associée à l'objet, y compris son nom de propriété, est disponible pour la collecte des déchets. L'instruction delete est abordée plus en détail dans la section "Libération des objets".
  • Utilisez le mot-clé var. Toute variable créée sans le mot-clé var est créée à l'échelle globale et n'est jamais éligible à la collecte des déchets, ce qui présente une opportunité de fuite de mémoire.

J'imagine que les pratiques devraient s'appliquer à tous les moteurs JavaScript (dans les différents navigateurs), bien que, comme il s'agit d'un site Apple, ils mai être quelque peu spécifique à Safari. (Peut-être quelqu'un pourrait-il clarifier ce point ?)

J'espère que cela vous aidera.

28 votes

Le guide d'Apple est défectueux : l'auteur utilise delete incorrectement ; par exemple, dans le premier exemple, au lieu de delete foo vous devez d'abord supprimer l'écouteur d'événement via window.removeEventListener() et ensuite utiliser foo = null pour écraser la variable ; dans IE, delete window.foo (mais pas delete foo ) aurait également fonctionné si foo était global, mais même dans ce cas, il ne le serait pas dans FF ou Opera

3 votes

Sachez que l'article d'Eric doit être considéré comme "à des fins historiques uniquement". Mais il est tout de même instructif.

2 votes

Notez également qu'IE 6 et 7 n'utilisent PAS de collecteur de déchets non générationnel de type mark-and-sweep. Ils utilisent un simple compteur de références, qui est plus vulnérable aux problèmes de références circulaires avec le ramasse-miettes.

56voto

Christoph Points 64389

Attention aux références circulaires lorsque des objets DOM sont impliqués :

Fuites de mémoire en JavaScript

N'oubliez pas que la mémoire ne peut être récupérée que lorsqu'il n'y a plus de références actives à l'objet. Il s'agit d'un piège courant avec les fermetures et les gestionnaires d'événements, car certains moteurs JS ne vérifient pas quelles variables sont réellement référencées dans les fonctions internes et conservent simplement toutes les variables locales des fonctions englobantes.

Voici un exemple simple :

function init() {
    var bigString = new Array(1000).join('xxx');
    var foo = document.getElementById('foo');
    foo.onclick = function() {
        // this might create a closure over `bigString`,
        // even if `bigString` isn't referenced anywhere!
    };
}

Une implémentation naïve de JS ne peut pas collecter bigString tant que le gestionnaire d'événement est présent. Il y a plusieurs façons de résoudre ce problème, par exemple en fixant bigString = null à la fin de init() ( delete ne fonctionnera pas pour les variables locales et les arguments de fonction : delete supprime les propriétés des objets, et la variable objet est inaccessible - ES5 en mode strict va même lancer un ReferenceError si vous essayez de supprimer une variable locale !).

Je recommande d'éviter autant que possible les fermetures inutiles si vous vous souciez de la consommation de mémoire.

21 votes

Le bug de la référence circulaire DOM est spécifique à JScript -- aucun autre navigateur n'en souffre à part IE. En fait, je suis presque sûr que la spécification ECMAScript stipule explicitement que le GC doit être capable de gérer de tels cycles :-/

0 votes

@olliej : Je ne vois aucune mention de la CG dans le document de travail de la Commission. Spécification ECMAScript .

0 votes

17voto

TStamper Points 17163

Bonne citation tirée d'un blog

Le composant DOM est "garbage collected", tout comme le composant JScript, ce qui signifie que si vous créez un objet dans l'un ou l'autre de ces composants, et que vous perdez ensuite la trace de cet objet, il sera finalement nettoyé.

Par exemple :

function makeABigObject() {
var bigArray = new Array(20000);
}

Lorsque vous appelez cette fonction, le composant JScript crée un objet (appelé bigArray) qui est accessible dans la fonction. Cependant, dès que la fonction revient, vous "perdez la trace" de bigArray car il n'y a plus aucun moyen d'y faire référence. Le composant JScript se rend compte que vous en avez perdu la trace, et donc bigArray est nettoyé - sa mémoire est récupérée. Le même genre de chose fonctionne dans le composant DOM. Si vous dites document.createElement('div') ou quelque chose de similaire, alors le composant DOM crée un objet pour vous. Si vous perdez la trace de cet objet d'une manière ou d'une autre, le composant DOM nettoiera ce qui s'y rapporte.

13voto

Heat Miser Points 6305

À ma connaissance, les objets JavaScript sont ramassés périodiquement lorsqu'il ne reste plus de références à l'objet. C'est quelque chose qui se produit automatiquement, mais si vous voulez en savoir plus sur la façon dont cela fonctionne, au niveau du C++, il est judicieux de jeter un coup d'œil à la page de l'application WebKit ou Code source V8

En général, vous n'avez pas besoin d'y penser, mais dans les anciens navigateurs, comme IE 5.5 et les premières versions d'IE 6, et peut-être les versions actuelles, les fermetures créent des références circulaires qui, lorsqu'elles ne sont pas vérifiées, finissent par consommer de la mémoire. Dans le cas particulier dont je parle à propos des fermetures, c'est lorsque vous ajoutez une référence JavaScript à un objet DOM, et un objet à un objet DOM qui renvoie à l'objet JavaScript. En fait, ces fuites ne pouvaient jamais être collectées et finissaient par rendre le système d'exploitation instable dans les applications de test qui tournaient en boucle pour créer des plantages. En pratique, ces fuites sont généralement faibles, mais pour garder votre code propre, vous devriez supprimer la référence JavaScript à l'objet DOM.

En général, c'est une bonne idée d'utiliser le mot-clé delete pour déréférencer immédiatement les gros objets comme les données JSON que vous avez reçues en retour et dont vous avez fait ce que vous deviez en faire, en particulier dans le développement Web mobile. Cela permet au prochain balayage du GC de supprimer cet objet et de libérer sa mémoire.

0 votes

Le problème de référence circulaire JavaScript -> DOM -> JavaScript est-il résolu dans les nouvelles versions d'IE ? Si oui, depuis quand ? Je pensais qu'il était architecturalement très profond et peu probable qu'il soit jamais corrigé. Avez-vous des sources ?

0 votes

Juste à titre anecdotique. Je n'ai pas remarqué de fuites importantes dans IE 8 fonctionnant en mode standard, et non en mode dégradé. Je vais ajuster ma réponse.

1 votes

@erikkallen : oui, le bogue GC a été corrigé dans les versions 8+ d'IE, car les plus anciennes utilisaient un algorithme de garbage collection très naïf, qui rendait impossible le GC d'une paire d'objets se référant l'un à l'autre. Les versions les plus récentes mark-and-sweep algorithmes de style s'occuper de cela .

5voto

mtasic85 Points 1223

"En informatique, le garbage collector (GC) est une forme de gestion automatique de la mémoire. Le ramasseur de déchets, ou simplement collecteur, tente de récupérer les déchets, c'est-à-dire la mémoire utilisée par les objets qui ne seront plus jamais accédés ou mutés par l'application."

Tous les moteurs JavaScript ont leurs propres collecteurs de déchets, et ils peuvent différer. La plupart du temps, vous n'avez pas à vous en occuper car ils font simplement ce qu'ils sont censés faire.

L'écriture d'un meilleur code dépend essentiellement de votre connaissance des principes de programmation, du langage et d'une mise en œuvre particulière.

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