1. Mécanisme de recyclage des ordures - GC
JavaScript possède un mécanisme automatique de collecte des ordures (GC: Collection Garbage), ce qui signifie que l'environnement d'exécution est responsable de la gestion de la mémoire utilisée lors de l'exécution du code.
Principe: Le collecteur des ordures périodiquement (périodique) trouve des variables qui ne sont pas utilisées puis libèrent leur mémoire.
Le mécanisme de la collection de déchets JavaScript est très simple: découvrez des variables qui ne sont plus utilisées puis libèrent la mémoire qu'il occupe. Cependant, ce processus n'est pas en temps réel car ses frais généraux sont relativement importants, donc le collecteur des ordures s'exécutera périodiquement à des intervalles de temps fixe .
Les variables qui ne sont plus utilisées sont des variables qui terminent le cycle de vie. Bien sûr, ils ne peuvent être que des variables locales. Le cycle de vie de la variable globale ne se terminera pas tant que le navigateur désinstallera la page. Les variables locales n'existent que lors de l'exécution de la fonction, et dans ce processus, l'espace correspondant sera alloué aux variables locales sur la pile ou le tas pour stocker leurs valeurs, puis ces variables sont utilisées dans la fonction jusqu'à la fin de la fonction. Cependant, en raison des fonctions internes dans la fermeture, les fonctions externes ne peuvent pas être considérées comme une fin.
Expliquons simplement le code:
fonction fn1 () {var obj = {name: 'hanzichi', Âge: 10};} fonction fn2 () {var obj = {name: 'hanzichi', âge: 10}; return obj;} var a = fn1 (); var b = fn2 ();Voyons comment le code est exécuté. Premièrement, deux fonctions sont définies, appelées FN1 et FN2. Lorsque FN1 est appelé, l'entrée dans l'environnement FN1 ouvrira un objet de stockage de mémoire {nom: 'Hanzichi', Âge: 10}. Une fois l'appel terminé et l'environnement FN1 est sorti, le bloc de mémoire sera automatiquement libéré par le collecteur des ordures dans le moteur JS; Pendant le processus de FN2 appelé, l'objet retourné est pointé par la variable globale B, de sorte que le bloc de mémoire ne sera pas libéré.
Ici, la question se pose: quelle variable est inutile? Par conséquent, le collecteur des ordures doit suivre quelle variable est inutile et marque des variables qui ne sont plus utiles pour récupérer sa mémoire à l'avenir. Les stratégies de variables inutiles utilisées pour tag peuvent différer selon la mise en œuvre, et il existe généralement deux façons de procéder: marquer la clairance et le comptage des références. Le comptage des citations n'est pas très courant, la compensation de marque est plus couramment utilisée.
2. Marque claire
La méthode de collecte des ordures la plus couramment utilisée en JS est l'élimination de la marque. Lorsqu'une variable entre dans l'environnement, par exemple, déclare une variable dans une fonction, elle marque la variable comme "Entrez dans l'environnement". Logiquement parlant, la mémoire occupée par des variables entrant dans l'environnement ne peut pas être libérée, car elles peuvent être utilisées tant que le flux d'exécution entre dans l'environnement correspondant. Et lorsqu'une variable quitte l'environnement, elle est marquée comme "hors de l'environnement".
fonction test () {var a = 10; // est marqué, entrez l'environnement var b = 20; // est marqué, entrez dans l'environnement} test (); // Après l'exécution, A et B sont marqués, quittent l'environnement et sont recyclés.Lorsque le collecteur des ordures fonctionne, il marque toutes les variables stockées en mémoire (bien sûr, toute méthode de marquage peut être utilisée). Il supprime ensuite les balises (fermetures) des variables dans l'environnement et les variables référencées par des variables dans l'environnement. Les variables marquées après cela seront considérées comme des variables prêtes à être supprimées car les variables dans l'environnement ne peuvent plus accéder à ces variables. Enfin, le collecteur des ordures termine le travail de compensation de la mémoire, détruisant ces valeurs marquées et récupérant l'espace mémoire qu'ils occupent.
Jusqu'à présent, les implémentations JS de IE, Firefox, Opera, Chrome et Safari utilisent des stratégies de collecte de déchets de marque de marque ou des stratégies similaires, mais les intervalles de temps de collecte des ordures sont différents les uns des autres.
3. Coutrage
La signification du nombre de références est de garder une trace du nombre de fois que chaque valeur est référencée. Lorsqu'une variable est déclarée et qu'une valeur de type de référence est attribuée à la variable, le nombre de références à cette valeur est 1. Si la même valeur est attribuée à une autre variable, le nombre de références à la valeur est augmenté de 1. Au contraire, si la variable contenant la référence à cette valeur prend une autre valeur, le nombre de références à cette valeur est réduite. L'espace qu'il occupe peut être récupéré. De cette façon, lorsque le collecteur des ordures s'étend à nouveau la prochaine fois, il libère de la mémoire qui valorise avec 0 références.
fonction test () {var a = {}; // Le nombre de références de a est 0 var b = a; // Le nombre de références de a est 1 var c = a; // Le nombre de références de A est 1, et le nombre de références de A est 1, et le nombre de références de A est 1, et le nombre de références de A est 2 var b = {}; // Le nombre de références de A est 1, et le nombre de références de A est 1}Netscape Navigator3 a été le premier navigateur à utiliser la stratégie de comptage de référence, mais bientôt il a rencontré un problème sérieux: références circulaires. Une référence circulaire fait référence à un objet A contenant un pointeur vers l'objet B, et l'objet B contient également une référence à l'objet A.
fonction fn () {var a = {}; var b = {}; a.pro = b; b.pro = a;} fn ();Les temps de référence de A et B ci-dessus sont 2. Une fois Fn () exécuté, les deux objets ont quitté l'environnement. Il n'y a pas de problème dans le mode de compensation Mark. Cependant, sous la stratégie de comptage de référence, car les temps de référence de A et B ne sont pas 0, la mémoire ne sera pas collectée par le collecteur des ordures. Si la fonction FN est appelée en grande quantité, une fuite de mémoire se produira. Sur IE7 et IE8, la mémoire augmente fortement.
Nous savons que certains objets dans IE ne sont pas des objets JS natifs. Par exemple, les objets du DOM et de la BOM sont implémentés sous la forme d'objets COM à l'aide de C ++, et le mécanisme de collecte des ordures des objets COM adopte une stratégie de comptage de référence. Par conséquent, même si le moteur IE JS adopte une stratégie de compensation de balises, les objets COM accessibles par JS sont toujours basés sur la stratégie de comptage de référence. En d'autres termes, tant que les objets COM sont impliqués dans IE, il y aura un problème de références circulaires.
var element = document.getElementById ("some_element"); var myObject = new Object (); myObject.e = element; element.o = myObject;Cet exemple crée une référence circulaire entre un élément DOM et un objet JS natif. Parmi eux, la variable MyObject a un attribut nommé élément pointant vers l'objet élément; et l'élément variable a également un attribut nommé O pour se référer à MyObject. En raison de cette référence circulaire, même si le DOM dans l'exemple est supprimé de la page, il ne sera jamais recyclé.
En regardant l'exemple ci-dessus, certains étudiants pensaient que c'était trop faible. Qui ferait une chose aussi ennuyeuse? En fait, le faisons-nous?
window.onload = fonction outerFunction () {var obj = document.getElementById ("élément"); obj.onclick = fonction innerFunction () {};};Ce code semble être bien, mais OBJ fait référence à Document.GetElementById ("Element"), et la méthode onClick de document.getElementById ("élément") fera référence à la variable allemande dans l'environnement externe, qui inclut naturellement OBJ. N'est-ce pas très caché?
Solution
Le moyen le plus simple consiste à déférer manuellement la boucle, par exemple, la fonction peut le faire.
myObject.Element = null; element.o = null;
window.onload = fonction outerFunction () {var obj = document.getElementById ("élément"); obj.onclick = fonction innerFunction () {}; obj = null;};Définir une variable sur NULL signifie couper la connexion entre la variable et la valeur qu'elle a précédemment référencée. Lorsque le collecteur des ordures fonctionne la prochaine fois, ces valeurs sont supprimées et la mémoire qu'ils occupent est recyclée.
Il convient de noter que IE9 + n'a pas de référence circulaire pour provoquer des fuites de mémoire DOM. Il se peut que Microsoft l'ait optimisé, ou que la méthode de recyclage de Dom a changé.
4. Gestion de la mémoire
1. Quand la collection Garbage sera-t-elle déclenchée?
Le collecteur des ordures fonctionne périodiquement. Si la mémoire allouée est très grande, le travail de recyclage sera très difficile. La détermination de l'intervalle de temps de collecte des ordures devient une question qui mérite d'être réfléchie. La collection d'ordonnance d'IE6 fonctionne selon l'allocation de mémoire. Lorsqu'il y a 256 variables, 4096 objets et 64k chaînes dans l'environnement, le collecteur de déchets sera déclenché. Il a l'air très scientifique et il n'a pas besoin d'être appelé de temps en temps. Parfois, c'est inutile. N'est-il pas bon d'appeler à la demande comme ça? Mais s'il y a tellement de variables dans l'environnement, et que les scripts sont si complexes et normaux maintenant, alors le résultat est que le collecteur des ordures fonctionne toujours, donc le navigateur ne peut pas jouer.
Microsoft a fait des ajustements dans IE7. Les conditions de déclenchement ne sont plus fixes, mais modifiées dynamiquement. La valeur initiale est la même que IE6. Si l'allocation de mémoire collectée par le collecteur des ordures représente moins de 15% de la mémoire occupée par le programme, cela signifie que la plupart de la mémoire ne peut pas être recyclée. Les conditions de déclenchement de la collecte des ordures définies sont trop sensibles. À ce moment, doublez les conditions de la rue. Si la mémoire collectée est supérieure à 85%, cela signifie que la majeure partie de la mémoire doit être nettoyée il y a longtemps. À l'heure actuelle, les conditions de déclenchement sont en retrait. Cela fait que le recyclage des ordures fonctionne plus de fonctions
2. Solution GC raisonnable
1) La solution GC de base du moteur JavaScript est (simple GC): Marque et balayage, c'est-à-dire:
2) défauts GC
Comme d'autres langues, la politique GC de JavaScript ne peut pas éviter un problème: lorsque GC, arrêtez de répondre à d'autres opérations, qui sont pour des raisons de sécurité. Le GC de JavaScript est de 100 ms ou même au-dessus, ce qui est bon pour les applications générales, mais pour les jeux JS, les applications qui nécessitent une cohérence élevée sont gênantes. C'est ce que le nouveau moteur a besoin pour optimiser: éviter la réponse d'arrêt à long terme causée par GC.
3) Stratégie d'optimisation GC
L'oncle David a principalement introduit deux solutions d'optimisation, et ce sont également les deux solutions d'optimisation les plus importantes:
(1) Génération GC)
Cela est conforme à l'idée de stratégie de recyclage Java. Le but est de faire la distinction entre les objets "temporaires" et "persistants"; Recyclez plus de zones «objets temporaires» et les zones moins «objets titulaires», réduisez les objets qui doivent être traversés à chaque fois, réduisant ainsi le temps passé sur GCS à chaque fois. Comme indiqué dans l'image:
Ce qui doit être ajouté ici, c'est que pour l'objet de génération titulaire, il y a des frais généraux supplémentaires: migrez-le de la jeune génération à la génération titulaire, et si elle est référencée, la référence pointant doit également être modifiée.
(2) GC incrémentiel
L'idée de ce plan est très simple, qui est de "traiter un peu à chaque fois, de gérer un peu la prochaine fois, et ainsi de suite". Comme indiqué dans l'image:
Bien que cette solution prenne un peu de temps, elle a de nombreuses interruptions, ce qui entraîne le problème de la commutation de contexte fréquente.
Étant donné que chaque solution a ses scénarios et ses inconvénients applicables, dans les applications réelles, la solution sera sélectionnée en fonction de la situation réelle.
Par exemple: lorsque le rapport (objet / s) est faible, la fréquence de l'exécution de GC est interrompue et le GC simple est inférieur; Si un grand nombre d'objets sont "survécu" pendant longtemps, l'avantage du traitement générationnel n'est pas excellent.
L'article ci-dessus comprend de manière approfondie le mécanisme de recyclage de la collecte des ordures de Javascirp est tout le contenu que je partage avec vous. J'espère que cela pourra vous donner une référence et j'espère que vous pourrez soutenir Wulin.com plus.