Explication détaillée du mécanisme de collecte des ordures Java
À première vue, ce que fait la collecte des ordures devrait être exactement comme son nom l'indique : trouver et supprimer les ordures. En fait, c'est tout le contraire. Le garbage collection garde une trace de tous les objets encore utilisés et marque les objets restants comme des déchets. Dans cet esprit, examinons de plus près comment ce recyclage automatisé de la mémoire appelé « garbage collection » est implémenté dans la JVM.
Gestion manuelle de la mémoire
Avant de présenter la version moderne du garbage collection, passons brièvement en revue l'époque où la mémoire devait être explicitement allouée et libérée manuellement. Si vous oubliez de libérer la mémoire, cette mémoire ne pourra pas être réutilisée. Cette mémoire est occupée mais non utilisée. Ce scénario est appelé fuite de mémoire.
Ce qui suit est un exemple simple de gestion manuelle de la mémoire écrite en C :
int send_request() { size_t n = read_size(); int *elements = malloc(n * sizeof(int)); if(read_elements(n, elements) < n) { // elements not freed! return -1; } // … free(elements) return 0; }
Comme vous pouvez le voir, vous pouvez facilement oublier pour libérer la mémoire. Les fuites de mémoire étaient un problème très courant. Vous ne pouvez les combattre qu'en corrigeant constamment votre code. Par conséquent, il est nécessaire de trouver un moyen plus élégant de libérer automatiquement la mémoire inutilisée afin de réduire le risque d’erreur humaine. Ce processus automatisé est également appelé garbage collection (GC en abrégé).
Pointeurs intelligents
Une des premières mises en œuvre de la collecte automatique des déchets est le comptage de références. Vous savez combien de fois chaque objet a été référencé. Lorsque le compteur atteint 0, l'objet peut être recyclé en toute sécurité. Le pointeur partagé de C est un exemple très célèbre :
int send_request() { size_t n = read_size(); stared_ptr<vector<int>> elements = make_shared<vector<int>>(); if(read_elements(n, elements) < n) { return -1; } return 0; }
Le sharedptr que nous utilisons enregistrera le nombre de fois que cet objet est référencé. Le nombre est incrémenté de un si vous le transmettez à quelqu'un d'autre, et décrémenté de un lorsqu'il est hors de portée. Une fois que ce nombre atteint 0, sharedptr supprimera automatiquement le vecteur correspondant sous-jacent. Bien sûr, ce n’est qu’un exemple, car certains lecteurs ont souligné qu’il est peu probable que cela se produise dans la réalité, mais cela suffit à titre de démonstration.
Gestion automatique de la mémoire
Dans le code C ci-dessus, nous devons également indiquer explicitement que nous devons utiliser la gestion de la mémoire. Alors que se passerait-il si tous les objets utilisaient ce mécanisme ? C'est tellement pratique que les développeurs n'ont pas à penser à nettoyer la mémoire. Le runtime saura automatiquement quelle mémoire n’est plus utilisée et la libérera. En d’autres termes, il recycle automatiquement les déchets. Le garbage collector de première génération a été introduit en Lisp en 1959, et la technologie a continué d'évoluer jusqu'à ce jour.
Comptage de références
L'idée que nous venons de démontrer en utilisant le pointeur partagé de C peut être appliquée à tous les objets. De nombreux langages, tels que Perl, Python et PHP, utilisent cette approche. Cela peut être facilement expliqué avec une image :
Le nuage vert représente les objets encore utilisés dans le programme. D'un point de vue technique, c'est un peu comme une variable locale dans une méthode en cours d'exécution, ou une variable statique. La situation peut varier selon les langages de programmation, ce n’est donc pas notre objectif.
Les cercles bleus représentent les objets en mémoire et vous pouvez voir combien d'objets y font référence. Les objets entourés de cercles gris ne sont plus référencés par personne. Par conséquent, ce sont des objets poubelles et peuvent être nettoyés par le ramasse-miettes.
Ça a l'air bien, non ? Oui, mais il y a un défaut majeur. Il est facile d'apparaître des anneaux isolés. Les objets qu'ils contiennent ne appartiennent à aucun domaine, mais ils se réfèrent les uns aux autres, ce qui donne un numéro de référence non nul. Voici un exemple :
Comme vous pouvez le constater, la partie rouge est en fait un objet poubelle qui n'est plus utilisé par l'application. En raison d'un défaut dans le comptage de références, il y aura une fuite de mémoire.
Il existe plusieurs façons de résoudre ce problème, comme utiliser des références spéciales "faibles", ou utiliser un algorithme spécial pour recycler les références circulaires. Les langages mentionnés précédemment tels que Perl, Python et PHP utilisent tous des méthodes similaires pour recycler les références circulaires, mais cela dépasse le cadre de cet article. Nous allons présenter en détail la méthode utilisée par la JVM.
Marquer la suppression
Tout d'abord, la définition de l'accessibilité des objets par la JVM doit être plus claire. Il n'est pas aussi vague qu'avant avec un nuage vert, mais a une définition très claire et spécifique de l'objet racine du garbage collection (Garbage Collection Roots) :
Variables locales
Fil d'activité
Champs statiques
Référence JNI
D'autres (seront discutés plus tard)
JVM enregistre tous les objets accessibles (survie) via l'algorithme de marquage et de suppression, tout en garantissant que la mémoire des objets inaccessibles peut être réutilisée. Cela se compose de deux étapes :
Le marquage fait référence au parcours de tous les objets accessibles, puis à l'enregistrement des informations de ces objets dans la mémoire locale
Suppression Garantira que l’adresse mémoire de l’objet inaccessible pourra être utilisée lors de la prochaine allocation de mémoire.
Différents algorithmes GC dans la JVM, tels que Parallel Scavenge, Parallel Mark Copy et CMS sont tous des implémentations différentes de cet algorithme, mais chaque étape est légèrement différente sur le plan conceptuel, elles correspondent toujours. deux étapes mentionnées ci-dessus.
La chose la plus importante à propos de cette implémentation est qu'il n'y aura plus de fuites de boucles d'objets :
L'inconvénient est que le thread d'application doit être suspendu pour terminer le recyclage si la référence est conservée. en changeant, vous êtes incapable de compter. La situation dans laquelle l'application est mise en pause afin que la JVM puisse s'occuper de ses tâches est également connue sous le nom de pause Stop The World (STW). Il existe de nombreuses possibilités pour déclencher cette pause, mais le garbage collection est probablement la plus courante.
Merci d'avoir lu, j'espère que cela pourra vous aider, merci pour votre soutien à ce site !
Pour plus d'articles liés au mécanisme de récupération de place Java, veuillez faire attention au site Web PHP chinois !