Maison  >  Article  >  Java  >  Une explication détaillée du garbage collection Java

Une explication détaillée du garbage collection Java

高洛峰
高洛峰original
2017-01-17 15:49:251284parcourir

1. L'idée de base de l'algorithme de collecte des ordures
Le langage Java a établi un mécanisme de collecte des ordures pour suivre les objets en cours d'utilisation et découvrir et recycler les objets qui ne sont plus utilisés (référencés). Ce mécanisme peut prévenir efficacement deux dangers pouvant survenir lors de l'allocation dynamique de mémoire : l'épuisement de la mémoire provoqué par un gaspillage de mémoire excessif et les références de mémoire illégales provoquées par une libération de mémoire inappropriée.

L'idée principale de l'algorithme de récupération de place est d'identifier les objets dans l'espace mémoire disponible pour la machine virtuelle, c'est-à-dire l'espace de tas. Si l'objet est référencé, il est appelé vivant. objet. Au contraire, si l'objet n'est plus référencé, il est appelé un objet vivant. Une référence est un objet poubelle, et l'espace qu'elle occupe peut être recyclé pour être réaffecté. Le choix de l'algorithme de garbage collection et l'ajustement raisonnable des paramètres du système de garbage collection affectent directement les performances du système, les développeurs doivent donc avoir une compréhension plus approfondie.

2. Conditions de déclenchement du GC (Garbage Collector) principal
La JVM effectue très fréquemment des GC secondaires, mais comme ce GC prend très peu de temps, il a peu d'impact sur le système. Ce qui mérite plus d’attention est la condition de déclenchement du GC principal, car elle a un impact significatif sur le système. En général, deux conditions déclencheront le GC principal :

(1) Lorsque l'application est inactive, c'est-à-dire lorsqu'aucun thread d'application n'est en cours d'exécution, le GC sera appelé. Étant donné que le GC est effectué dans le thread ayant la priorité la plus basse, le thread GC ne sera pas appelé lorsque l'application est occupée, sauf dans les conditions suivantes.

(2) Lorsque la mémoire du tas Java est insuffisante, GC sera appelé. Lorsque le thread d'application est en cours d'exécution et crée de nouveaux objets pendant le processus en cours, si l'espace mémoire est insuffisant à ce moment-là, la JVM appellera de force le thread GC pour récupérer de la mémoire pour de nouvelles allocations. Si les exigences d'allocation de mémoire ne peuvent pas être satisfaites après un GC, la JVM effectuera deux GC supplémentaires pour d'autres tentatives. Si les exigences ne peuvent toujours pas être satisfaites, la JVM signalera une erreur « mémoire insuffisante » et l'application Java s'arrêtera. .

Étant donné que l'exécution ou non du GC principal est décidée par la JVM en fonction de l'environnement système et que l'environnement système est en constante évolution, le fonctionnement du GC principal est incertain et il est impossible de prédire quand il le fera inévitablement. se produire, mais ce qui est certain, c'est que pour une application de longue durée, le GC principal est effectué à plusieurs reprises.

3. Mesures visant à réduire les frais généraux du GC
Selon le mécanisme GC ci-dessus, le fonctionnement du programme affectera directement les changements dans l'environnement du système, affectant ainsi le déclenchement du GC. Si vous ne concevez pas et ne codez pas selon les caractéristiques du GC, il y aura une série d'effets négatifs tels que la rétention de mémoire. Afin d’éviter ces effets, le principe de base est de réduire autant que possible les déchets et les frais généraux du processus GC. Les mesures spécifiques incluent les aspects suivants :

(1) Ne pas appeler explicitement System.gc()
Cette fonction recommande que la JVM effectue le GC principal. Bien qu'il ne s'agisse que d'une suggestion et non d'une garantie, dans. dans de nombreux cas, cela déclenchera le GC principal, augmentant ainsi la fréquence du GC principal, c'est-à-dire augmentant le nombre de pauses intermittentes. Ce qui nécessite une attention particulière ici, c'est que l'appel à System.gc() affiché dans le code n'est pas nécessairement capable d'effectuer GC. Nous pouvons le vérifier via la méthode finalize(), c'est-à-dire en appelant activement System.gc(), pas nécessairement à chaque fois. La méthode finalize() est appelée à chaque fois. La caractéristique de la méthode finalize() est que la méthode finalize() est d'abord appelée avant que l'objet ne soit recyclé.

(2) Minimiser l'utilisation d'objets temporaires
Les objets temporaires deviendront des déchets après avoir sauté des appels de fonction. Utiliser moins de variables temporaires équivaut à réduire la génération de déchets, prolongeant ainsi le deuxième problème mentionné ci-dessus. . Le moment où une condition de déclenchement se produit réduit le risque de GC principal.

(3) Il est préférable de définir explicitement l'objet sur Null lorsqu'il n'est pas utilisé
De manière générale, les objets Null seront traités comme des déchets, il est donc avantageux de définir explicitement les objets inutilisés sur Null Le collecteur GC détermine les déchets, améliorant ainsi l'efficacité du GC.

(4) Essayez d'utiliser StringBuffer au lieu de String pour accumuler des chaînes (voir un autre article de blog sur String et StringBuffer en JAVA pour plus de détails)
Puisque String est un objet chaîne de longueur fixe, accumulez des objets String lorsque , au lieu de se développer dans un objet String, un nouvel objet String est recréé, tel que Str5=Str1 Str2 Str3 Str4 Plusieurs objets poubelle seront générés lors de l'exécution de cette instruction, car chaque fois que l'opération " " est effectuée, De nouveaux objets String doivent être créés, mais ces objets de transition n'ont aucune signification pratique pour le système et ne feront qu'ajouter davantage de déchets. Pour éviter cette situation, vous pouvez utiliser StringBuffer pour accumuler des chaînes. Étant donné que StringBuffer est de longueur variable, il se développe sur la base d'origine et ne produit pas d'objets intermédiaires.

(5) Vous pouvez utiliser des types de base tels que Int et Long au lieu des objets Integer et Long
Les variables de type de base occupent beaucoup moins de ressources mémoire que les objets correspondants. Si ce n'est pas nécessaire, il est préférable de le faire. utilisez des variables de base. Quand devez-vous utiliser Integer ?

(6) Utilisez le moins possible les variables d'objet statiques
Les variables statiques sont des variables globales et ne seront pas recyclées par GC. Elles occuperont toujours de la mémoire.

(7) Répartir le temps de création ou de suppression d'objets
Concentrer la création d'un grand nombre de nouveaux objets sur une courte période de temps, notamment les objets volumineux, se traduira par un besoin soudain d'un grand quantité de mémoire. Face à cette situation, la JVM uniquement le GC principal peut être effectuée pour récupérer de la mémoire ou consolider des fragments de mémoire, augmentant ainsi la fréquence du GC principal. Le même principe s'applique à la suppression centralisée d'objets. Cela provoque l'apparition soudaine d'un grand nombre d'objets indésirables et l'espace libre diminuera inévitablement, augmentant ainsi considérablement les chances de forcer le GC principal lors de la prochaine création d'un nouvel objet.

4. Algorithme de collecte des déchets
(1) Collecteur de comptage de références
Le comptage de références est une des premières stratégies de collecte des déchets. Dans cette approche, chaque objet du tas a un décompte de références. Lorsqu'un objet est créé et qu'une référence à l'objet est affectée à une variable, le nombre de références de l'objet est défini sur 1. Par exemple, créez un nouvel objet A a=new A(); puis a est affecté à une autre variable b, c'est-à-dire b=a alors le nombre de références de l'objet a est 1. Lorsqu'une référence à cet objet est attribuée à une autre variable, le décompte est incrémenté de un. Lorsqu'une référence à un objet dépasse la durée de vie ou est définie sur une nouvelle valeur, le nombre de références de l'objet est décrémenté de 1. Par exemple, si b=c, le nombre de références de a est -1. Tout objet avec un nombre de références de 0 peut être récupéré. Lorsqu'un objet est récupéré, le nombre d'objets auxquels il fait référence est décrémenté de un. Dans cette approche, le garbage collection d’un objet peut conduire à des actions de garbage collection ultérieures pour d’autres objets. Par exemple, A a=new A();b=a; lorsque b est récupéré, le nombre de références de a devient 0, ce qui fait que a est également récupéré.

Avantages de la méthode : Le collecteur de comptage de références peut être exécuté rapidement et est étroitement lié au fonctionnement du programme. Ce rappel est utile dans les environnements en temps réel où le programme ne peut pas être interrompu pendant de longues périodes. Inconvénients de la méthode

 : Le comptage de références ne peut pas détecter les cycles (c'est-à-dire que deux objets ou plus se réfèrent les uns aux autres). Un exemple de boucle est qu'un objet parent a une référence à un objet enfant, et l'objet enfant fait à son tour référence à l'objet parent. De cette manière, il est impossible pour les utilisateurs d'objets d'avoir un décompte égal à 0, même s'ils ne sont plus joignables par l'objet racine du programme en cours d'exécution. Un autre inconvénient est que chaque augmentation ou diminution du nombre de références entraîne une surcharge supplémentaire.

(2) Collecteur de traçage
La détection des déchets est généralement implémentée en créant une collection d'objets racine et en vérifiant l'accessibilité à partir de ces objets racine. Un objet est accessible s'il existe un chemin de référence entre l'objet racine accessible au programme en cours d'exécution et l'objet. L'objet racine est toujours accessible au programme. A partir de ces objets racines, tout objet pouvant être touché est considéré comme un objet « actif ». Les objets qui ne peuvent pas être touchés sont considérés comme des déchets car ils n'affectent plus l'exécution future du programme.

Le collecteur de traçage suit le graphique de référence d'objet à partir du nœud racine. Les objets rencontrés lors du suivi sont marqués d'une certaine manière. En général, placez le marqueur sur l'objet lui-même ou utilisez un bitmap séparé pour définir le marqueur. Une fois le suivi terminé, les objets non marqués sont inaccessibles et peuvent être collectés.

L'algorithme de suivi de base est appelé « marquer et effacer ». Le nom fait référence aux deux étapes des téléphones portables indésirables. Pendant la phase de marquage, le garbage collector parcourt l'arborescence de référence et marque chaque objet rencontré. Pendant la phase de nettoyage, les objets non marqués sont libérés et la mémoire obtenue après la libération des objets est renvoyée au programme en cours d'exécution. Dans la machine virtuelle Java, l'étape de nettoyage doit inclure la finalisation de l'objet.

Pour des explications plus approfondies et détaillées sur le garbage collection Java et les articles connexes, veuillez faire attention au site Web PHP chinois !

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn