
Le garbage collection est un mécanisme caché de JavaScript .Nous n'avons généralement pas à nous soucier du garbage collection, nous devons simplement nous concentrer sur le développement de fonctions. Mais cela ne signifie pas que nous pouvons nous asseoir et nous détendre lors de l'écriture JavaScript . À mesure que les fonctions que nous implémentons deviennent de plus en plus complexes et que la quantité de code s'accumule, les problèmes de performances deviennent de plus en plus importants. Comment écrire du code qui s'exécute plus rapidement et occupe moins de mémoire est la quête sans fin des programmeurs. Un excellent programmeur peut toujours obtenir des résultats étonnants avec des ressources extrêmement limitées. C'est aussi la différence entre les êtres ordinaires et les dieux distants.
le code poubelle ? Lors de leur exécution dans la mémoire de l'ordinateur, toutes les variables, objets et fonctions que nous définissons dans le code occuperont une certaine quantité d'espace mémoire dans la mémoire. Dans les ordinateurs, l'espace mémoire est une ressource très limitée. Il faut toujours faire attention à l'utilisation de la mémoire. Après tout, les modules de mémoire sont très chers ! Une variable, une fonction ou un objet peut être qualifié de déchet s'il n'est plus nécessaire pour l'exécution ultérieure du code après sa création.
Bien qu'il soit très facile de comprendre intuitivement la définition d'un déchet, pour un programme informatique, il nous est difficile de conclure à un moment donné que les variables, fonctions ou objets actuellement existants ne seront plus utilisés dans le futur. Afin de réduire le coût de la mémoire informatique et d'assurer l'exécution normale des programmes informatiques, nous stipulons généralement que les objets ou variables qui remplissent l'une des conditions suivantes sont des déchets :
les variables ou les objets qui ne sont pas référencés sont équivalents à une maison sans porte. On ne peut jamais y entrer, il est donc impossible de les utiliser. Même si les objets inaccessibles sont connectés, ils restent inaccessibles de l’extérieur et ne peuvent donc plus être utilisés. Les objets ou variables qui remplissent les conditions ci-dessus ne seront plus jamais utilisés lors de l'exécution future du programme, ils peuvent donc être traités en toute sécurité comme un garbage collection.
Lorsque nous clarifions les objets qui doivent être supprimés à travers la définition ci-dessus, cela signifie-t-il qu'il n'y a pas de déchets dans les variables et objets restants ?
Non! Les déchets que nous identifions actuellement ne représentent qu'une partie de tous les déchets. Il y aura encore d'autres déchets qui ne rempliront pas les conditions ci-dessus, mais ils ne seront plus utilisés.
Peut-on dire que les déchets qui répondent à la définition ci-dessus sont des « déchets absolus » et que les autres déchets cachés dans le programme sont des « déchets relatifs » ?
Le mécanisme de garbage collection ( GC,Garbage Collection ) est responsable du recyclage des variables inutiles et de l'espace mémoire occupé lors de l'exécution du programme. Le phénomène selon lequel un objet existe toujours en mémoire même s'il n'a aucune possibilité d'être réutilisé est appelé fuite de mémoire . Les fuites de mémoire sont un phénomène très dangereux, en particulier dans les programmes de longue durée. Si un programme présente une fuite de mémoire, il occupera de plus en plus d’espace mémoire jusqu’à manquer de mémoire.
Les chaînes, les objets et les tableaux n'ont pas de taille fixe, donc leur allocation dynamique de stockage ne peut être effectuée que si leur taille est connue. Chaque fois qu'un programme JavaScript crée une chaîne, un tableau ou un objet, l'interpréteur alloue de la mémoire pour stocker l'entité. Chaque fois que la mémoire est allouée dynamiquement de cette manière, elle doit éventuellement être libérée pour pouvoir être réutilisée ; sinon, l'interpréteur JavaScript consommera toute la mémoire disponible dans le système, provoquant un crash du système.
Le mécanisme de récupération de place de JavaScript vérifiera par intermittence les variables et les objets inutiles (garbage) et libérera l'espace qu'ils occupent.
Différents langages de programmation adoptent différentes stratégies de garbage collection. Par exemple, C++ n'a pas de mécanisme de garbage collection. Toute la gestion de la mémoire repose sur les propres compétences du programmeur, ce qui rend C++ plus difficile à maîtriser. JavaScript utilise l'accessibilité pour gérer la mémoire. Littéralement, l'accessibilité signifie accessible, ce qui signifie que le programme peut accéder et utiliser les variables et les objets d'une manière ou d'une autre. La mémoire occupée par ces variables ne peut pas être libérée.
JavaScript spécifie un ensemble inhérent de valeurs accessibles, et les valeurs de l'ensemble sont intrinsèquement accessibles :
les autres variables internes sont appelées racines , qui sont les nœuds supérieurs de l'arborescence d'accessibilité.
Une variable ou un objet est considéré comme accessible s'il est utilisé directement ou indirectement par la variable racine.
En d’autres termes, une valeur est accessible si elle peut être atteinte via la racine (par exemple Abcde ).
let people = {
les garçons :{
garçons1 : {nom : 'xiaoming'},
garçons2 : {nom : 'xiaojun'},
},
filles:{
filles1 : {nom : 'xiaohong'},
filles2 : {nom : 'huahua'},
}}; Le code ci-dessus crée un objet et l'affecte à la variable people . La variable people contient deux objets, boys et girls , et boys et girls contiennent respectivement deux sous-objets. Cela crée également une structure de données contenant 3 niveaux de relations de référence (indépendamment des données de type de base), comme indiqué ci-dessous :

Parmi eux, le nœud people est naturellement accessible car il s’agit d’une variable globale. Les nœuds boys et girls sont indirectement accessibles car ils sont directement référencés par des variables globales. boys1 , boys2 , girls1 et girls2 sont également des variables accessibles car elles sont indirectement utilisées par les variables globales et sont accessibles via people.boys.boys .
Si nous ajoutons le code suivant après le code ci-dessus :
people.girls.girls2 = null; people.girls.girls1 = people.boys.boys2
Alors, le diagramme hiérarchique de référence ci-dessus deviendra le suivant :

Parmi eux, girls1 et girls2 sont devenus des nœuds inaccessibles en raison de la déconnexion du nœud grils , ce qui signifie qu'ils seront recyclés par le mécanisme de collecte des ordures.
Et si à ce moment-là, on exécute le code suivant :
people.boys.boys2 = null
alors le diagramme hiérarchique de référence deviendra le suivant :
À l'heure actuelle, bien que les nœuds boys et boys2 soient déconnectés, en raison de la relation de référence entre boys2 et girls , boys2 est toujours accessible et ne sera pas recyclé par le mécanisme de récupération de place.
Le diagramme d'association ci-dessus prouve pourquoi la valeur équivalente de la variable globale est appelée racine , car dans le diagramme d'association, ce type de valeur apparaît généralement comme le nœud racine de l'arbre des relations.
laissez les gens = {
les garçons :{
garçons1 : {nom : 'xiaoming'},
garçons2 : {nom : 'xiaojun'},
},
filles:{
filles1 : {nom : 'xiaohong'},
filles2 : {nom : 'huahua'},
}};people.boys.boys2.girlfriend = people.girls.girls1;
//boys2 fait référence à girls1people.girls.girls1.boyfriend = people.boys.boys2; //girls1 fait référence à boys2 Le code ci-dessus crée une relation interdépendante entre boys2 et girls1 .

A ce stade, si l'on coupe l'association entre boys et boys2 :
supprimez people.boys.boys2 ;
le schéma d'association entre les objets est le suivant :

Évidemment, il n’y a aucun nœud inaccessible.
À ce stade, si nous coupons la relation boyfriend :
supprimez people.girls.girls1,
le diagramme de relation devient :

À l'heure actuelle, bien qu'il existe toujours une relation girlfriend entre boys2 et girls1 , boys2 devient un nœud inaccessible et sera récupéré par le mécanisme de collecte des ordures.
laissez les gens = {
les garçons :{
garçons1 : {nom : 'xiaoming'},
garçons2 : {nom : 'xiaojun'},
},
filles:{
filles1 : {nom : 'xiaohong'},
filles2 : {nom : 'huahua'},
}};delete people.boys;delete people.girls; Le diagramme hiérarchique de référence formé par le code ci-dessus est le suivant :

À l'heure actuelle, bien qu'il existe toujours une relation de référence mutuelle entre les objets à l'intérieur de la boîte en pointillés, ces objets sont également inaccessibles et seront supprimés par le mécanisme de récupération de place. Ces nœuds ont perdu leur relation avec la racine et deviennent inaccessibles.
Le soi-disant comptage des références, comme son nom l'indique, compte chaque fois qu'un objet est référencé. L'ajout d'une référence l'augmentera de un, et la suppression d'une référence la diminuera de un. le nombre devient 0, il est considéré comme Garbage, supprimant ainsi les objets pour récupérer de la mémoire.
Par exemple :
let user = {username:'xiaoming'} ;
//L'objet est référencé par la variable utilisateur, compte +1
laissez user2 = utilisateur ;
//L'objet est référencé par une nouvelle variable, et le compte +1
utilisateur = nul ;
//La variable ne fait plus référence à l'objet, le compte est -1
utilisateur2 = nul ;
//La variable ne fait plus référence à l'objet, nombre impair -1
//À l'heure actuelle, le nombre de références d'objets est de 0 et sera supprimé. Bien que la méthode de comptage de références semble très raisonnable, en fait, il existe des failles évidentes dans le mécanisme de recyclage de mémoire utilisant la méthode de comptage de références.
Par exemple :
let boy = {} ;
laissez fille = {} ;
garçon.petite amie = fille ;
fille.boyfriend = garçon ;
garçon = nul ;
girl = null; Le code ci-dessus a des références mutuelles entre boy et girl . Le comptage supprime les références dans boy et girl , et les deux objets ne seront pas recyclés. En raison de l'existence de références circulaires, les compteurs de références des deux objets anonymes ne reviendront jamais à zéro, ce qui entraînera une fuite de mémoire.
Il existe un concept de pointeur intelligent ( shared_ptr ) en C++ . Les programmeurs peuvent utiliser le pointeur intelligent pour utiliser le destructeur d'objet afin de libérer le décompte de références. Cependant, des fuites de mémoire se produiront dans le cas de références circulaires.
Heureusement, JavaScript a adopté une autre stratégie plus sûre, qui évite davantage le risque de fuite de mémoire.
Marquer mark and sweep est un algorithme de récupération de place adopté par le moteur JavaScript . Son principe de base est de partir de la racine , de parcourir d'abord la relation de référence entre les variables et de mettre une marque (优秀员工徽章) sur les variables parcourues. . Les objets non marqués sont finalement supprimés.
Le processus de base de l'algorithme est le suivant :
2 jusqu'à ce qu'il n'y ait plus de nouvelle adhésion d'employés Excellent ;Par exemple :
s'il existe une relation de référence d'objet dans notre programme comme indiqué ci-dessous :

Nous pouvons clairement voir qu'il y a une "île accessible" sur le côté droit de l'image entière. En partant de la racine , l'île ne peut jamais être atteinte. Mais le garbage collector n'a pas la perspective de Dieu comme la nôtre. Il marquera uniquement le nœud racine comme un employé exceptionnel sur la base de l'algorithme.

Partez ensuite des employés exceptionnels et recherchez tous les nœuds cités par les employés exceptionnels, comme les trois nœuds dans la case en pointillés dans la figure ci-dessus. Marquez ensuite les nœuds nouvellement trouvés comme employés exceptionnels.

Le processus de recherche et de marquage est répété jusqu'à ce que tous les nœuds pouvant être trouvés soient marqués avec succès.

Finalement, l'effet montré dans la figure ci-dessous est obtenu :

Étant donné que les îlots de droite ne sont toujours pas marqués après la fin du cycle d'exécution de l'algorithme, ces nœuds ne pourront pas être atteints par la tâche du ramasse-miettes et seront éventuellement effacés.
Les enfants qui ont étudié les structures de données et les algorithmes pourraient être surpris de découvrir qu’il s’agit d’un parcours de graphes, similaire aux algorithmes de graphes connectés.
Le garbage collection est une tâche à grande échelle, en particulier lorsque la quantité de code est très importante, l'exécution fréquente de l'algorithme de garbage collection ralentira considérablement l'exécution du programme. L'algorithme JavaScript a apporté de nombreuses optimisations dans le garbage collection pour garantir que le programme puisse être exécuté efficacement tout en assurant l'exécution normale du travail de recyclage.
Les stratégies adoptées pour l'optimisation des performances incluent généralement les points suivants :
Les programmes JavaScriptJavaScript un nombre considérable de variables pendant l'exécution, et l'analyse fréquente de ces variables entraînera une surcharge importante. Cependant, ces variables ont leurs propres caractéristiques dans le cycle de vie. Par exemple, les variables locales sont fréquemment créées, utilisées rapidement, puis supprimées, tandis que les variables globales occupent la mémoire pendant longtemps. JavaScript gère les deux types d'objets séparément. Pour les variables locales qui sont rapidement créées, utilisées et supprimées, le garbage collector analysera fréquemment pour garantir que ces variables sont rapidement nettoyées après avoir perdu leur utilisation. Pour les variables qui conservent la mémoire pendant une longue période, réduisez la fréquence de leur vérification, économisant ainsi une certaine quantité de surcharge.
L'idée incrémentielle est très courante dans l'optimisation des performances et peut également être utilisée pour le garbage collection. Lorsque le nombre de variables est très important, il faut évidemment beaucoup de temps pour parcourir toutes les variables en même temps et attribuer des notes exceptionnelles aux employés, ce qui entraîne des retards lors de l'exécution du programme. Par conséquent, le moteur divisera le travail de récupération de place en plusieurs sous-tâches et exécutera progressivement chaque petite tâche pendant l'exécution du programme. Cela entraînera un certain délai de récupération, mais n'entraînera généralement pas de retards évidents dans le programme.
CPU fonctionne pas toujours, même dans les programmes complexes. Cela est principalement dû au fait que CPU fonctionne très rapidement et que IO périphériques sont souvent plusieurs ordres de grandeur plus lentes. Par conséquent, c'est une bonne idée d'organiser une stratégie de récupération de place lorsque CPU est en panne. inactif. Il s'agit d'une méthode d'optimisation des performances très efficace et n'aura fondamentalement aucun effet négatif sur le programme lui-même. Cette stratégie est similaire à la mise à niveau du temps d'inactivité du système, et les utilisateurs ne sont pas du tout conscients de l'exécution en arrière-plan.
La tâche principale de cet article est simplement de mettre fin aux mécanismes de récupération de place, aux stratégies et méthodes d'optimisation couramment utilisées. Il n'est pas destiné à donner à chacun une compréhension approfondie des principes d'exécution en arrière-plan du moteur.
Grâce à cet article, vous devez comprendre :
JavaScript , qui est exécuté en arrière-plan et ne nous oblige pas à nous en soucier ;