Qu'est-ce que la récupération de place JavaScript? Qu'est-ce qui est important pour un programmeur Web de comprendre le garbage collection JavaScript, afin d'écrire un meilleur code?
Qu'est-ce que la récupération de place JavaScript? Qu'est-ce qui est important pour un programmeur Web de comprendre le garbage collection JavaScript, afin d'écrire un meilleur code?
Réponses:
Eric Lippert a écrit un article de blog détaillé sur ce sujet il y a quelque temps (en le comparant également à VBScript ). Plus précisément, il a écrit sur JScript , qui est la propre implémentation d'ECMAScript par Microsoft, bien que très similaire à JavaScript. J'imagine que vous pouvez supposer que la grande majorité du comportement serait la même pour le moteur JavaScript d'Internet Explorer. Bien sûr, l'implémentation variera d'un navigateur à l'autre, bien que je soupçonne que vous pourriez prendre un certain nombre de principes communs et les appliquer à d'autres navigateurs.
Cité de cette page:
JScript utilise un ramasse-miettes non générationnel à balayage et à balayage. Cela fonctionne comme ceci:
Chaque variable qui est "dans la portée" est appelée un "récupérateur". Un charognard peut faire référence à un nombre, un objet, une chaîne, peu importe. Nous maintenons une liste de récupérateurs - les variables sont déplacées vers la liste scav lorsqu'elles entrent dans la portée et hors de la liste scav lorsqu'elles sortent de la portée.
De temps en temps, le garbage collector s'exécute. Tout 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 supplémentaires inutilisés dans cette structure, nous en définissons donc juste un.)
Deuxièmement, il efface la marque sur les charognards et la fermeture transitive des références de charognards. Donc, si un objet récupérateur fait référence à un objet non embarqué, nous effaçons les bits sur le non récupérateur et sur tout ce à quoi il se réfère. (J'utilise le mot «fermeture» dans un sens différent de celui de mon post précédent.)
À ce stade, nous savons que toute la mémoire encore marquée est une mémoire allouée qui ne peut être atteinte par aucun chemin à partir d'une variable dans la portée. Tous ces objets sont invités à se détruire, ce qui détruit toutes les références circulaires.
Le but principal de la récupération de place est de permettre au programmeur de ne pas se soucier de la gestion de la mémoire des objets qu'il crée et utilise, bien que, bien sûr, il ne soit pas possible de l'éviter parfois - il est toujours avantageux d'avoir au moins une idée approximative du fonctionnement de la récupération de place. .
Note historique: une révision antérieure de la réponse avait une référence incorrecte à l' delete
opérateur. En JavaScript, l' delete
opérateur supprime une propriété d'un objet et est complètement différent de delete
C / C ++.
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()
, puis utiliser foo = null
pour remplacer la variable; dans IE, delete window.foo
(mais pas delete foo
) aurait également fonctionné s'il foo
était global, mais même dans FF ou Opera
delete
est un opérateur unaire (une expression), pas une instruction (ie:) delete 0, delete 0, delete 3
. Il ressemble à une déclaration lorsqu'il est exprimé par une déclaration d'expression.
Méfiez-vous des références circulaires lorsque des objets DOM sont impliqués:
Modèles de fuite de mémoire en JavaScript
Gardez à l'esprit que la mémoire ne peut être récupérée qu'en l'absence 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 JS naïve ne peut pas être collectée bigString
tant que le gestionnaire d'événements est présent. Il existe plusieurs façons de résoudre ce problème, par exemple la définition 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 l'objet variable est inaccessible - ES5 en mode strict lancera même un ReferenceError
si vous essayez pour supprimer une variable locale!).
Je recommande d'éviter autant que possible les fermetures inutiles si vous vous souciez de la consommation de mémoire.
Bonne citation tirée d'un blog
Le composant DOM est "récupéré", tout comme le composant JScript, ce qui signifie que si vous créez un objet dans l'un des composants, puis perdez 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 (nommé bigArray) accessible dans la fonction. Cependant, dès que la fonction revient, vous "perdez la trace" de bigArray car il n'y a plus moyen de s'y référer. Eh bien, 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, le composant DOM crée un objet pour vous. Une fois que vous perdez la trace de cet objet d'une manière ou d'une autre, le composant DOM nettoiera le connexe.
Au meilleur de ma connaissance, les objets JavaScript sont régulièrement récupérés quand il n'y a plus de références à l'objet. C'est quelque chose qui se produit automatiquement, mais si vous voulez en savoir plus sur son fonctionnement, au niveau C ++, il est logique de jeter un œil au code source WebKit ou V8
En règle générale, vous n'avez pas besoin d'y penser, cependant, dans les navigateurs plus anciens, comme IE 5.5 et les premières versions d'IE 6, et peut-être les versions actuelles, les fermetures créeraient des références circulaires qui, si elles n'étaient pas cochées, finiraient par consommer de la mémoire. Dans le cas particulier que je veux dire sur les fermetures, c'est lorsque vous avez ajouté une référence JavaScript à un objet dom et un objet à un objet DOM qui renvoyait à l'objet JavaScript. Fondamentalement, il ne pourrait jamais être collecté et entraînerait finalement l'instabilité du système d'exploitation dans les applications de test qui faisaient une boucle pour créer des plantages. En pratique, ces fuites sont généralement petites, mais pour garder votre code propre, vous devez supprimer la référence JavaScript à l'objet DOM.
Habituellement, c'est une bonne idée d'utiliser le mot clé delete pour déréférencer immédiatement les gros objets tels que les données JSON que vous avez reçues et faire tout ce que vous devez en faire, en particulier dans le développement Web mobile. Cela provoque le prochain balayage du GC pour supprimer cet objet et libérer sa mémoire.
mark-and-sweep
algorithmes de style plus récents s'en occupent .
garbage collection (GC) est une forme de gestion automatique de la mémoire en supprimant les objets qui ne sont plus nécessaires.
tout processus traitant de la mémoire, procédez comme suit:
1 - allouez l'espace mémoire dont vous avez besoin
2 - faire un peu de traitement
3 - Libérez cet espace mémoire
il existe deux algorithmes principaux utilisés pour détecter quels objets ne sont plus nécessaires.
Collecte des ordures de comptage de références : cet algorithme réduit la définition de "un objet n'est plus nécessaire" à "un objet n'a aucun autre objet s'y référant", l'objet sera supprimé s'il n'y a pas de point de référence
Algorithme de marquage et de balayage : connectez chaque objet à la source racine. aucun objet ne se connecte à root ou à un autre objet. cet objet sera supprimé.
actuellement les navigateurs les plus modernes utilisant le deuxième algorithme.
"En informatique, le garbage collection (GC) est une forme de gestion automatique de la mémoire. Le garbage collector, ou simplement le collector, tente de récupérer les déchets, ou la mémoire utilisée par des objets qui ne seront plus jamais accédés ou mutés par l'application."
Tous les moteurs JavaScript ont leurs propres récupérateurs de place et peuvent différer. La plupart du temps, vous n'avez pas à vous occuper d'eux car ils font simplement ce qu'ils sont censés faire.
L'écriture d'un meilleur code dépend principalement de votre connaissance des principes de programmation, du langage et de l'implémentation particulière.
Qu'est-ce que la récupération de place JavaScript?
vérifier ça
Qu'est-ce qui est important pour un programmeur Web de comprendre le garbage collection JavaScript, afin d'écrire un meilleur code?
En Javascript, vous ne vous souciez pas de l'allocation de mémoire et de la désallocation. L'ensemble du problème est demandé à l'interpréteur Javascript. Des fuites sont toujours possibles en Javascript, mais ce sont des bugs de l'interpréteur. Si vous êtes intéressé par ce sujet, vous pouvez en lire plus sur www.memorymanagement.org
Sur Windows, vous pouvez utiliser Drip.exe pour trouver des fuites de mémoire ou vérifier si votre routine mem gratuite fonctionne.
C'est vraiment simple, il suffit d'entrer une URL de site Web et vous verrez la consommation de mémoire du moteur de rendu IE intégré. Appuyez ensuite sur Actualiser, si la mémoire augmente, vous avez trouvé une fuite de mémoire quelque part sur la page Web. Mais cela est également très utile pour voir si les routines de libération de mémoire fonctionnent pour IE.
Les types de référence ne stockent pas l'objet directement dans la variable à laquelle il est affecté, de sorte que la variable objet dans cet exemple ne contient pas réellement l'instance d'objet. Au lieu de cela, il contient un pointeur (ou une référence) vers l'emplacement en mémoire où l'objet existe
var object = new Object();
si vous affectez une variable à une autre, chaque variable obtient une copie du pointeur et toutes deux font toujours référence au même objet en mémoire.
var object1 = new Object();
var object2 = object1;
JavaScript est un langage récupéré , vous n'avez donc pas vraiment à vous soucier des allocations de mémoire lorsque vous utilisez des types de référence. Cependant, il est préférable de déréférencer les objets dont vous n'avez plus besoin pour que le garbage collector puisse libérer cette mémoire. La meilleure façon de procéder consiste à définir la variable objet sur null.
var object1 = new Object();
// do something
object1 = null; // dereference
Le déréférencement d' objets est particulièrement important dans les très grandes applications qui utilisent des millions d'objets.
des principes du JavaScript orienté objet - NICHOLAS C. ZAKAS