Cet article présente d'abord brièvement les méthodes courantes de garbage collection, puis analyse le principe de collecte du collecteur G1, ses avantages par rapport aux autres garbage collector, et donne enfin quelques pratiques de réglage.
Tout d'abord, avant de comprendre G1, nous devons savoir clairement, qu'est-ce que le ramassage des ordures ? En termes simples, le garbage collection consiste à recycler les objets qui ne sont plus utilisés en mémoire.
Étapes de base de la collecte des déchets
Il y a 2 étapes dans le recyclage :
Trouver les objets qui ne sont plus utilisés en mémoire
Libérer la mémoire occupée par ces objets
1 Trouver les objets qui ne sont plus utilisés dans la mémoire
La question est alors de savoir comment déterminer. quels objets ne sont plus utilisés ? Nous avons également 2 méthodes :
Méthode de comptage de référence c'est si un objet n'est référencé par aucun Si la référence pointe vers lui, cela peut être considéré comme un déchet. L'inconvénient de cette méthode est qu'elle ne peut pas détecter l'existence de l'algorithme de recherche racine. L'idée de base de l'algorithme de recherche de racine est d'utiliser une série de L'objet nommé "GC Roots" est utilisé comme point de départ, en partant de ces nœuds et en recherchant vers le bas le chemin parcouru par la recherche. s'appelle la chaîne de référence. Lorsqu'un objet n'a pas de chaîne de référence connectée aux racines GC, il est prouvé que cet objet n'est pas disponible. Maintenant que nous savons comment trouver les objets poubelles, comment nettoyer ces objets . 2. Libérez la mémoire occupée par ces objetsLes méthodes courantes incluent la copie ou le nettoyage direct, mais le nettoyage direct entraînera une fragmentation de la mémoire, donc des méthodes de nettoyage et de compression seront produites En général, là. Il existe trois types d'algorithmes de recyclage. 🎜>1. Mark-Copy
Il divise la capacité de mémoire disponible en deux blocs de taille égale et n'en utilise qu'un à la fois. utilisé, le reste sera utilisé. 🎜>Copiez l'objet
dans un autre bloc, puis effacez immédiatement l'espace mémoire utilisé. Ses avantages sont une implémentation simple, une efficacité élevée et l'absence de fragmentation de la mémoire. sa gestion nécessite 2 fois plus de mémoire. 2. Marquage-Nettoyage L'algorithme de marquage et d'effacement est divisé en deux étapes : "marquage" et "effacement" : marquez d'abord le. objets qui doivent être recyclés, puis effacer les objets uniformément une fois le marquage terminé. L'avantage est une grande efficacité, mais l'inconvénient est qu'il est sujet à la fragmentation de la mémoire3. >L'opération de marquage est cohérente avec l'algorithme "mark-clean". L'opération ultérieure ne consiste pas seulement à nettoyer l'objet directement, mais après avoir nettoyé les objets inutiles, tous les objets survivants sont déplacés vers une extrémité et les pointeurs référençant leur les objets sont mis à jour. Parce que les objets sont déplacés, c'est moins efficace que "mark-clean", mais cela ne produit pas de fragmentation de la mémoire.
Hypothèses basées sur la génération
Depuis le temps de survie. des objets est long et court, pour les objets avec des temps de survie longs, réduire le nombre de fois qu'ils sont gc peut éviter une surcharge inutile. La mémoire est divisée en la nouvelle génération et l'ancienne génération. La nouvelle génération stocke les objets nouvellement créés et les objets avec. une durée de survie relativement courte, et l'ancienne génération stocke des objets avec une durée de survie relativement longue. De cette façon, seule la jeune génération est nettoyée à chaque fois, et l'ancienne génération n'est nettoyée que lorsque cela est nécessaire, ce qui peut grandement améliorer l'efficacité du GC et gagner du temps.
Historique du garbage collector Java
La première étape, Serial collector
Avant jdk1.3.1, la machine virtuelle Java ne pouvait utiliser que le Serial collector . Le collecteur série est un collecteur monothread, mais sa signification « monothread » ne signifie pas seulement qu'il n'utilisera qu'un seul processeur ou un seul thread de collecte pour terminer le travail de garbage collection, mais plus important encore, lorsqu'il effectue le garbage collection, tous les autres threads de travail doivent être mis en pause jusqu'à ce que leur collecte soit terminée.
PS : Comment activer le collecteur série
-XX:+UseSerialGC
Deuxième étape, collecteur parallèle (parallèle)
Collecteur parallèle Également connu En tant que collecteur de débit, par rapport au collecteur série, le principal avantage de Parallel est l'utilisation de multi-threads pour effectuer le travail de nettoyage des ordures, ce qui peut exploiter pleinement les caractéristiques du multicœur et réduire considérablement le temps de gc.
PS : Comment activer le collecteur parallèle
-XX:+UseParallelGC -XX:+UseParallelOldGC
La troisième étape, le collecteur CMS (concurrent)
Le collecteur CMS mettra en pause tous les threads d'application pendant le GC mineur et effectuera le garbage collection de manière multithread. Pendant le Full GC, le thread d'application n'est plus suspendu. Au lieu de cela, plusieurs threads d'arrière-plan sont utilisés pour analyser régulièrement l'espace d'ancienne génération et recycler les objets qui n'y sont plus utilisés en temps opportun.
PS : Comment activer le collecteur CMS
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC
La quatrième étape, collecteur G1 (simultané)
Le collecteur G1 (ou garbage-first collector) est conçu pour minimiser les pauses lors du traitement de très gros tas (supérieurs à 4 Go). L'avantage par rapport au CMS est que le taux de génération de fragmentation de la mémoire est considérablement réduit.
PS : Comment activer le collecteur G1
-XX:+UseG1GC
Le premier article (Annexe 1) de G1 a été publié en 2004 et n'était disponible en jdk1.7u4 qu'en 2012. Oracle prévoit officiellement de faire de G1 le garbage collector par défaut dans jdk9 pour remplacer CMS. Pourquoi Oracle recommande-t-il fortement G1 ? Quels sont les avantages de G1 ?
Tout d'abord, le principe de conception de G1 est un réglage des performances simple et réalisable
Les développeurs n'ont qu'à déclarer les paramètres suivants :
-XX : + UseG1GC -Xmx32g -XX:MaxGCPauseMillis=200
Parmi eux -XX:+UseG1GC consiste à activer le garbage collector G1, -Xmx32g La mémoire maximale de la mémoire tas conçue est de 32 Go, -XX:MaxGCPauseMillis=200 définit le GC maximum. Le temps de pause est de 200 ms. Si nous avons besoin d'effectuer un réglage, lorsque la taille de la mémoire est certaine, il suffit de modifier le temps de pause maximum.
Deuxièmement, G1 annule la division de l'espace physique entre la nouvelle génération et l'ancienne génération.
De cette façon, nous n'avons plus besoin de placer chaque génération dans un espace séparé, et nous n'avons pas à nous soucier de savoir s'il y a suffisamment de mémoire pour chaque génération.
Au lieu de cela, l'algorithme G1 divise le tas en plusieurs régions (Régions), qui appartiennent toujours au collecteur générationnel. Cependant, une partie de ces zones inclut la nouvelle génération. Le garbage collection de la nouvelle génération utilise toujours la méthode de pause de tous les threads d'application et de copie des objets survivants vers l'ancienne génération ou l'espace Survivor. L'ancienne génération est également divisée en plusieurs zones, et le collecteur G1 termine le travail de nettoyage en copiant les objets d'une zone à une autre. Cela signifie que pendant le traitement normal, G1 termine la compression du tas (au moins une partie du tas), il n'y aura donc pas de problème de fragmentation de la mémoire cms.
Dans G1, il y a aussi une zone spéciale appelée zone Humongous. Si un objet occupe plus de 50 % de la capacité de la partition, le collecteur G1 le considère comme un objet géant. Ces objets géants seront alloués directement dans l'ancienne génération par défaut, mais s'il s'agit d'un objet géant de courte durée, cela aura un impact négatif sur le garbage collector. Afin de résoudre ce problème, G1 divise une zone Humongous, utilisée pour stocker des objets géants. Si un objet énorme ne peut pas tenir dans une partition H, G1 recherchera une partition H continue pour le stocker. Afin de trouver la zone H continue, il faut parfois démarrer Full GC.
PS : Dans Java 8, la génération persistante a également été déplacée vers l'espace mémoire tas ordinaire et remplacée par l'espace méta.
Stratégie d'allocation d'objets
En parlant d'allocation de gros objets, nous devons parler de la stratégie d'allocation d'objets. Il est divisé en 3 étapes :
TLAB (Thread Local Allocation Buffer) tampon d'allocation local de thread
Allocation dans la zone Eden
Allocation de zone énorme
TLAB alloue des tampons localement pour les threads. Son but est d'allouer des objets le plus rapidement possible. Si des objets sont alloués dans un espace partagé, nous devons utiliser un mécanisme de synchronisation pour gérer les pointeurs d'espace libre dans ces espaces. Dans l'espace Eden, chaque thread dispose d'une partition fixe pour allouer les objets, c'est-à-dire un TLAB. Lors de l'allocation d'objets, aucune synchronisation n'est requise entre les threads.
Pour les objets qui ne peuvent pas être alloués dans l'espace TLAB, la JVM tentera de les allouer dans l'espace Eden. Si l'espace Eden ne peut pas accueillir l'objet, l'espace ne peut être attribué qu'à l'ancienne génération.
Enfin, G1 propose deux modes GC, Young GC et Mixed GC, tous deux Stop The World (STW). Ci-dessous, nous présenterons respectivement ces deux modes.
Young GC effectue principalement du GC sur la zone Eden, qui sera déclenché lorsque l'espace Eden sera épuisé. Dans ce cas, les données de l'espace Eden sont déplacées vers l'espace Survivant. Si l'espace Survivant n'est pas suffisant, une partie des données de l'espace Eden sera directement promue vers l'espace ancienne génération. Les données de la zone Survivant sont déplacées vers la nouvelle zone Survivant, et certaines données sont également promues vers l'espace d'ancienne génération. Enfin, les données de l'espace Eden sont vides, le GC cesse de fonctionner et le thread d'application continue de s'exécuter.
À ce stade, nous devons réfléchir à une question Si nous GCons uniquement les objets de nouvelle génération, comment pouvons-nous trouver tous les objets. des objets racine ? Tous les objets sont-ils issus de l'ancienne génération ? Une telle analyse prendra beaucoup de temps. Par conséquent, G1 a introduit le concept de RSet. Son nom complet est Remembered Set et sa fonction est de suivre les références d'objet pointant vers une certaine zone de tas.
Dans CMS, il y a aussi le concept de RSet Il y a une zone dans l'ancienne génération pour enregistrer les références à la nouvelle génération. C'est un point important lors de l'exécution de Young GC, lors de l'analyse de la racine, seule cette zone doit être analysée, et il n'est pas nécessaire d'analyser l'intégralité de l'ancienne génération.
Mais dans G1, le pointage n'est pas utilisé. En effet, une partition est trop petite et il y a trop de partitions. Si le pointage est utilisé, cela entraînera beaucoup de déchets d'analyse. Certaines partitions ne nécessitent pas. Les références GC ont également été numérisées. Le point d’entrée est donc utilisé dans G1 pour le résoudre. Le point d'entrée signifie quelles partitions font référence aux objets de la partition actuelle. De cette façon, l'analyse de ces objets uniquement en tant que racines évite les analyses non valides. Puisqu’il existe plusieurs jeunes générations, est-il nécessaire d’enregistrer des références entre les nouvelles générations ? Cela n'est pas nécessaire car toutes les nouvelles générations seront analysées à chaque fois que la GC se produit, de sorte que seules les références de l'ancienne génération à la nouvelle génération doivent être enregistrées.
Il convient de noter que s'il y a de nombreux objets référencés, l'assignateur doit traiter chaque référence, et la surcharge de l'assignateur sera très importante. Afin de résoudre le problème de la surcharge de l'assignateur, un autre est introduit dans. Concept G1, table à cartes. Une table de cartes divise logiquement une partition en zones continues de taille fixe, et chaque zone est appelée une carte. Les cartes sont généralement plus petites, entre 128 et 512 octets. Card Table est généralement un octettableau, et l'adresse d'espace de chaque partition est identifiée par l'index de Card (c'est-à-dire l'indice du tableau). Par défaut, chaque carte n'est pas référencée. Lorsqu'un espace d'adressage est référencé, la valeur de l'index du tableau correspondant à cet espace d'adressage est marquée comme "0", c'est-à-dire marquée comme sale et référencée. De plus, RSet enregistre également l'indice du tableau. Dans des circonstances normales, ce RSet est en fait une table de hachage, la clé est l'adresse de départ d'une autre région, la valeur est un ensemble et les éléments à l'intérieur sont l'index de la table de cartes.
Phase Young GC :
Phase 1 : Root Scan
Les objets statiques et locaux sont scannés
Phase 2 : Mise à jour RS
Traiter la mise à jour de la file d'attente des cartes sales RS
Phase 3 : Traiter RS
Détecter les objets pointant de la jeune génération vers l'ancienne génération
Phase 4 : Copie d'objet
Copier l'objet survivant dans la zone survivant/ancienne
Phase 5 : Traiter la file d'attente de référence
Référence douce, référence faible , traitement de référence virtuelle
Mix GC effectue non seulement un garbage collection normal de nouvelle génération, mais recycle également certaines analyses en arrière-plan threads marqués Partition ancienne génération.
Ses étapes GC sont divisées en 2 étapes :
marquage concurrent global (marquage concurrent global)
Copier le survivant objet (évacuation)
Avant d'effectuer le Mix GC, un marquage simultané global sera effectué en premier. Quel est le processus d’exécution du marquage concurrent global ?
Dans G1 GC, il fournit principalement des services de marquage pour les GC mixtes et n'est pas une partie nécessaire d'un processus GC. Le processus d'exécution du marquage concurrent global est divisé en cinq étapes :
Marquage initial (STW)
Dans cette étape, G1 GC marque la racine. Cette phase est étroitement liée au ramassage régulier des déchets de la jeune génération (STW).
Scan de la région racine (scan de la région racine)
G1 GC scanne les références à l'ancienne génération dans la zone de survie initialement marquée et marque les objets référencés. Cette phase s'exécute en même temps que l'application (non-STW), et ce n'est qu'une fois cette phase terminée que le garbage collection de jeune génération STW suivant peut commencer.
Marquage simultané
G1 GC recherche dans tout le tas les objets accessibles (en direct). Cette phase se déroule concomitamment à l'application et peut être interrompue par le garbage collection STW jeune génération
Marquage final (Remarque, STW)
Cette phase est le garbage collection STW qui permet de compléter le cycle de marquage . G1 GC efface le tampon SATB, assure le suivi des objets actifs auxquels aucun accès n'a été effectué et effectue la gestion des références.
Cleanup, STW)
Dans cette phase finale, G1 GC effectue les opérations STW de statistiques et de purification RSet. Au cours de l'exercice comptable, G1 GC identifie les zones totalement libres et les zones disponibles pour la collecte mixte des déchets. La phase de nettoyage est partiellement simultanée car elle réinitialise la zone vide et la renvoie à la liste libre.
Algorithme de marquage à trois couleurs
En ce qui concerne le marquage simultané, nous devons comprendre l'algorithme de marquage à trois couleurs du marquage simultané. C'est un moyen utile de décrire un collecteur de traçage, et il peut être utilisé pour déduire l'exactitude du collecteur. Premièrement, nous divisons les objets en trois types.
Noir : L'objet racine, ou l'objet et ses sous-objets sont numérisés.
Gris : L'objet lui-même est numérisé, mais pas encore Après avoir scanné les sous-objets dans l'objet
Blanc : objets non analysés. Après avoir scanné tous les objets, les objets blancs finaux sont des objets inaccessibles, c'est-à-dire des objets poubelles
Lorsque le GC commence à numériser l'objet, suivez les étapes ci-dessous pour numériser l'objet :
L'objet racine est défini sur noir et le sous-objet est défini sur gris.
Continuez à parcourir à partir du gris et définissez les objets qui ont numérisé des sous-objets en noir.
Après avoir traversé tous les objets accessibles, tous les objets accessibles deviennent noirs. Les objets inaccessibles sont blancs et doivent être nettoyés.
Cela a l'air génial, mais si l'application est en cours d'exécution pendant le processus de marquage, le pointeur d'objet peut changer. Dans ce cas, nous rencontrerons un problème : problème de perte d'objet
Regardons la situation suivante, lorsque le garbage collector scanne la situation suivante :
A ce moment, l'application a effectué les opérations suivantes :
A.c=C
B.c=null
De cette façon, le diagramme d'état de l'objet devient le suivant :
À ce moment-là, lorsque le ramasse-miettes marquera et scannera à nouveau, cela ressemblera à ceci :
Évidemment, à l'heure actuelle, C is White est considéré comme un déchet et doit être nettoyé, ce qui est évidemment déraisonnable. Alors comment s’assurer que les objets marqués par GC ne sont pas perdus lors de l’exécution de l’application ? Il y a 2 manières possibles :
Enregistrer l'objet lors de l'insertion
Enregistrer l'objet lors de la suppression
Cela correspond aux deux méthodes d'implémentation différentes de CMS et G1 :
Dans CMS, la mise à jour incrémentielle est utilisée tant qu'elle se trouve dans la barrière en écriture, si une référence à un objet blanc est affectée. un champ d'un objet noir, l'objet blanc deviendra gris. Autrement dit, il est enregistré une fois inséré.
En G1, la méthode STAB (snapshot-at-the-beginning) est utilisée pour enregistrer tous les objets lors de la suppression. Elle comporte 3 étapes :
1, au début Lors du marquage, une. un graphique instantané est généré pour marquer les objets survivants
2. Lors du marquage simultané, tous les objets modifiés sont mis en file d'attente (dans la barrière d'écriture, tous les objets pointés par d'anciennes références deviennent non blancs)
3, il y aura peut-être des déchets gratuits, qui seront collectés la prochaine fois
De cette façon, G1 peut désormais savoir quelles anciennes partitions peuvent recycler le plus de déchets. Lorsque le marquage concurrent global est terminé, à un certain moment, Mix GC démarre. Ces garbage collection sont appelées « hybrides » car elles effectuent non seulement un garbage collection normal de jeune génération, mais collectent également certaines partitions marquées par le thread d'analyse en arrière-plan. La collecte des déchets mixtes est la suivante :
Le GC hybride utilise également une stratégie de nettoyage de copie. Lorsque le GC est terminé, l'espace sera à nouveau libéré.
À ce stade, le GC hybride a pris fin. Dans la section suivante, nous aborderons la pratique du réglage.
Réglage MaxGCPauseMillis
Les paramètres les plus élémentaires pour l'utilisation de GC ont été introduits plus tôt :
- XX : +UseG1GC -Xmx32g -XX:MaxGCPauseMillis=200
Les deux premiers paramètres sont faciles à comprendre. Comment configurer le dernier paramètre MaxGCPauseMillis ? Ce paramètre signifie littéralement le temps de pause maximum autorisé pour le GC. G1 essaie de garantir que chaque temps de pause GC se situe dans la plage MaxGCPauseMillis définie. Alors, comment le G1 atteint-il le temps de pause maximum ? Cela implique un autre concept, CSet (ensemble de collections). Cela signifie l'ensemble des zones collectées dans un ramasse-miettes.
Jeune GC : sélectionnez toutes les régions de la nouvelle génération. Contrôlez le coût du jeune GC en contrôlant le nombre de régions dans la nouvelle génération.
GC mixte : sélectionnez toutes les régions de la nouvelle génération, ainsi que plusieurs régions de l'ancienne génération avec des revenus de collecte élevés sur la base des statistiques mondiales de marquage simultané. Sélectionnez autant que possible la région de l'ancienne génération avec des revenus élevés dans le cadre de l'objectif de coût spécifié par l'utilisateur.
Après avoir compris cela, il nous sera plus facile de définir le temps de pause maximum. Tout d’abord, il existe une limite au temps de pause maximum que nous pouvons tolérer, et nous devons le fixer dans cette limite. Mais quelle valeur fixer ? Nous devons trouver un équilibre entre le débit et MaxGCPauseMillis. Si MaxGCPauseMillis est trop petit, le GC sera fréquent et le débit diminuera. Si MaxGCPauseMillis est trop grand, le temps de pause de l'application deviendra plus long. Le temps de pause par défaut de G1 est de 200 millisecondes. Nous pouvons commencer à partir d'ici et ajuster le temps approprié.
Autres paramètres de réglage
-XX:G1HeapRegionSize=n
La taille de la région G1 définie. Les valeurs sont des puissances de 2 et vont de 1 Mo à 32 Mo. L’objectif est de diviser environ 2 048 régions en fonction de la taille minimale du tas Java.
-XX:ParallelGCThreads=n
Définissez la valeur du nombre de threads de travail STW. Définissez la valeur de n sur le nombre de processeurs logiques. La valeur de n est la même que le nombre de processeurs logiques, jusqu'à un maximum de 8.
S'il y a plus de huit processeurs logiques, définissez la valeur de n à environ 5/8 du nombre de processeurs logiques. Cela fonctionne dans la plupart des cas, sauf pour les systèmes SPARC plus grands, où la valeur de n peut être d'environ 5/16 du nombre de processeurs logiques.
-XX:ConcGCThreads=n
Définissez le nombre de threads marqués en parallèle. Définissez n sur environ 1/4 du nombre de threads de récupération de place parallèles (ParallelGCThreads).
-XX:InitiatingHeapOccupancyPercent=45
Définit le seuil d'occupation du tas Java qui déclenche un cycle de marquage. L'occupation par défaut est de 45 % de l'ensemble du tas Java.
Évitez d'utiliser les paramètres suivants :
Évitez de définir explicitement la taille de la jeune génération à l'aide de l'option -Xmn ou d'autres options associées telles que -XX:NewRatio. Correction de la taille de la jeune génération qui remplace les objectifs de temps de pause.
Déclencher le GC complet
Dans certains cas, G1 déclenche le GC complet. À ce moment-là, G1 dégénérera et utilisera le collecteur série pour terminer le nettoyage des ordures. GC fonctionne et le temps de pause GC atteindra le deuxième niveau. L'ensemble de l'application est dans un état d'animation suspendue et ne peut gérer aucune demande. Bien entendu, notre programme ne veut pas voir cela. Alors, quelles sont les situations dans lesquelles le Full GC se produit ?
Échec du mode simultané
G1 démarre le cycle de marquage, mais l'ancienne génération est remplie avant Mix GC, et G1 abandonnera à ce moment-là Cycle de marquage du temps. Dans ce cas, vous devez augmenter la taille du tas ou ajuster le cycle (par exemple, augmenter le nombre de threads -XX:ConcGCThreads, etc.).
Échec de la promotion ou échec de l'évacuation
G1 n'a pas assez de mémoire pour les objets survivants ou les objets promus à utiliser lors de l'exécution du GC, ce qui déclenche Full CG. Vous pouvez voir (vers l'espace épuisé) ou (vers l'espace dépassé) dans le journal. La façon de résoudre ce problème est la suivante :
a, augmentez la valeur de l'option -XX:G1ReservePercent (et augmentez la taille totale du tas en conséquence) pour augmenter la quantité de mémoire réservée pour "l'espace cible".
b, démarrez le cycle de marquage plus tôt en réduisant -XX:InitiatingHeapOccupancyPercent.
c, vous pouvez également augmenter le nombre de fils de marquage parallèles en augmentant la valeur de l'option -XX:ConcGCThreads.
L'allocation d'objet géant a échoué
Lorsqu'un objet géant ne trouve pas d'espace approprié pour l'allocation, Full GC démarre pour libérer l'espace. Dans ce cas, vous devez éviter d'allouer un grand nombre d'objets géants, augmenter la mémoire ou augmenter -XX:G1HeapRegionSize pour que l'objet géant ne soit plus un objet géant.
En raison de l'espace limité, il existe de nombreuses pratiques de réglage pour G1, je ne les énumérerai donc pas toutes ici. Vous pouvez les explorer lentement dans votre pratique quotidienne. Enfin, j'attends avec impatience la sortie officielle de Java 9. Les performances de Java, qui utilise G1 comme garbage collector par défaut, s'amélioreront-elles à nouveau ?
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!