Sept types de garbage collectors JAVA

Ce document va expliquer ce qu’est le garbage collector en java et les principaux types de garbage collectors avec les comportements de chaque garbage collector. Veuillez également noter que dans cet article, je n’explique pas comment l’allocation du tas se produit et comment les collecteurs d’ordures majeurs/minor commencent. Il expliquera dans le prochain article.

Java est un langage de programmation orienté objet qui comprend la collecte automatique des ordures. Java alloue et désalloue automatiquement la mémoire afin que les programmes ne soient pas accablés par cette tâche. Aujourd’hui (Java-12), Java dispose de sept types de garbage collectors,

  1. Collecteur de déchets sériel
  2. Collecteur de déchets parallèle
  3. CMS Collecteur de déchets
  4. G1 Collecteur de déchets
  5. Epsilon Collecteur de déchets
  6. .

  7. Z garbage collector
  8. Shenandoah Garbage Collector

5ème et 6ème garbage collectors ont été introduits dans java 11 et le 7ème a été introduit dans java 12. Dans la plupart des applications en production a utilisé les quatre premiers types de garbage collectors. Depuis les trois derniers garbage collectors sont récemment entrés en scène.

Do we need to worry about GCs?

Oui, en effet. Nous devons nous préoccuper du GC et de ses comportements. Parce qu’Il peut fournir une différence de performance significative. Chaque GC a ses propres avantages et inconvénients. En tant que développeurs, nous devons avoir une idée claire sur les comportements de tous les garbage collectors et nous devons choisir un garbage collector en fonction de notre scénario d’entreprise. Nous pouvons choisir un garbage collector en, passant le choix comme un argument JVM.

Serial Garbage Collector

C’est l’implémentation de GC la plus simple. Elle est fondamentalement conçue pour un environnement à un seul thread. Cette implémentation GC gèle tous les threads de l’application lorsqu’elle s’exécute. Elle utilise un seul thread pour la collecte des ordures. Par conséquent, ce n’est pas une bonne idée de l’utiliser dans des applications multithreadées comme les environnements de serveur.

Pour activer le Serial Garbage Collector, nous pouvons utiliser l’argument suivant:

java -XX:+UseSerialGC -jar Application.java

Parallel Garbage Collector

Le garbage collector parallèle est également appelé comme un throughput collector. Contrairement au garbage collector série, celui-ci utilise plusieurs threads pour la collecte des déchets. Comme le collecteur de déchets en série, il gèle également tous les threads de l’application pendant la collecte des déchets. Le garbage collector convient mieux aux applications qui peuvent supporter des pauses applicatives.

Pour activer le garbage collector parallèle, nous pouvons utiliser l’argument suivant:

java -XX:+UseParallelGC -jar Application.java

Si nous utilisons ce GC, nous pouvons spécifier le nombre maximum de fils de garbage collector et le temps de pause, le débit et l’empreinte (taille du tas)

Le nombre de fils de garbage collector peut être contrôlé avec l’option de ligne de commande

-XX :ParallelGCThreads=<N>

L’objectif de temps de pause maximum (écart entre deux GC)est spécifié avec l’option de ligne de commande

-XX :MaxGCPauseMillis=<N>

L’objectif de débit maximal (mesuré en ce qui concerne le temps passé à faire la collecte des ordures par rapport au temps passé en dehors de la collecte des ordures) est spécifié par l’option de ligne de commande

-XX :GCTimeRatio=<N>

Une empreinte maximale du tas (la quantité de mémoire de tas qu’un programme requiert pendant son exécution) est spécifiée à l’aide de l’option -Xmx<N>.

CMS garbage collector

Le garbage collector CMS (Concurrent Mark Sweep) utilise plusieurs threads de garbage collector pour la collecte des déchets. Il scanne la mémoire du tas pour marquer les instances à évincer, puis balaie les instances marquées. Il est conçu pour les applications qui préfèrent des pauses de collecte des ordures plus courtes et qui peuvent se permettre de partager les ressources du processeur avec le collecteur d’ordures pendant que l’application est en cours d’exécution.

Le collecteur d’ordures CMS retient tous les threads de l’application dans les deux scénarios suivants uniquement

  1. Lors du marquage des objets référencés dans l’ancien espace de génération.
  2. Toute modification de la mémoire du tas en parallèle à la réalisation du garbage collector

Par rapport au garbage collector parallèle, le collector CMS utilise plus de CPU pour assurer un meilleur débit de l’application. Si nous pouvons allouer plus de CPU pour de meilleures performances, alors le CMS garbage collector est le choix préféré par rapport au collecteur parallèle.

Pour activer le CMS garbage collector, nous pouvons utiliser l’argument suivant:

java -XX:+USeParNewGC -jar Application.java

G1 Garbage Collector

G1 (Garbage First) Garbage Collector est conçu pour les applications fonctionnant sur des machines multiprocesseurs avec un grand espace mémoire. Il est disponible depuis la mise à jour 4 du JDK7 et dans les versions ultérieures.

Il sépare la mémoire du tas en régions et effectue la collecte dans celles-ci en parallèle. G1 fait également compacter l’espace libre du tas en cours de route juste après avoir récupéré la mémoire. Mais le collecteur de déchets CMS compacte la mémoire dans les situations d’arrêt du monde (STW). Le collecteur G1 remplacera le collecteur CMS car il est plus performant.

Dans le collecteur G1 contient deux phases;

  1. Marking
  2. Sweeping

À la différence des autres collecteurs, le collecteur G1 partitionne le tas en un ensemble de régions de tas de taille égale, chacune étant une plage contiguë de mémoire virtuelle. Lorsqu’il effectue des collectes de déchets, G1 montre une phase de marquage global simultané pour déterminer la vivacité des objets dans tout le tas.

Après que la phase de marquage soit terminée, G1 sait quelles régions sont principalement vides. Il collecte dans ces régions en premier, ce qui donne généralement une quantité importante d’espace libre. C’est pourquoi cette méthode de collecte de déchets est appelée Garbage-First.

Pour activer le collecteur de déchets G1, nous pouvons utiliser l’argument suivant :

java -XX:+UseG1GC -jar Application.java

Collecteur de déchets Epsilon

Epsilon est un collecteur de déchets non opérationnel ou passif. Il alloue la mémoire pour l’application, mais il ne collecte pas les objets inutilisés. Lorsque l’application épuise le tas Java, la JVM s’arrête. Cela signifie qu’Epsilon garbage collector permet, aux applications de manquer de mémoire et de se planter.

Le but de ce garbage collector est de mesurer et de gérer les performances des applications. Les garbage collectors actifs sont des programmes complexes qui s’exécutent à l’intérieur de la JVM aux côtés de votre application. Epsilon supprime l’impact du GC sur les performances. Il n’y a pas de cycles GC ni de barrières de lecture ou d’écriture. En utilisant le GC d’Epsilon, le code s’exécute de manière isolée. Epsilon aide à visualiser comment le garbage collection affecte les performances de l’application et quel est le seuil de mémoire puisqu’il indique quand il est épuisé. Par exemple, si nous pensons que nous n’avons besoin que d’un gigaoctet de mémoire pour notre application, nous pouvons l’exécuter avec -Xmx1g et voir le comportement. Si cette allocation de mémoire n’est pas suffisante, réexécutez-la avec un heap dump. Veuillez noter que nous devons activer cette option pour obtenir un vidage du tas. Nous pouvons utiliser cet argument pour obtenir un heap dump lorsque l’application se bloque à cause d’un manque de mémoire.

XX:HeapDumpOnOutOfMemoryError

Si nous devons presser chaque bit de performance de notre application, Epsilon pourrait être votre meilleure option pour un GC. Mais nous devons avoir une compréhension complète de la façon dont notre code utilise la mémoire. S’il ne crée presque pas de déchets ou si vous savez exactement combien de mémoire il utilise pour la période où il s’exécute, Epsilon est une option viable.

Pour activer le collecteur d’ordures Epsilon, nous pouvons utiliser l’argument suivant:

java -XX:+UseEpsilonGC -jar Application.java

Z garbage collector

ZGC effectue tous les travaux coûteux de manière simultanée, sans arrêter l’exécution des threads de l’application pendant plus de 10ms, ce qui le rend adapté aux applications qui nécessitent une faible latence et/ou utilisent un très grand tas. Selon la documentation d’Oracle, elle peut gérer des tas de plusieurs téraoctets. Oracle a introduit le ZGC dans Java 11. Le Z garbage collector effectue ses cycles dans ses threads. Il met l’application en pause pendant une moyenne de 1 ms. Les collecteurs G1 et Parallel ont une moyenne d’environ 200 ms.

En Java 12, Oracle a ajouté des correctifs de performance et le déchargement des classes, même si Z est toujours en statut expérimental. Il n’est disponible que sur Linux 64 bits. Mais, ZGC tire parti des pointeurs 64 bits avec une technique appelée coloration des pointeurs. Les pointeurs colorés stockent des informations supplémentaires sur les objets du tas. C’est l’une des raisons pour lesquelles elle est limitée à la JVM 64 bits. Cet article a été expliqué ce scénario profondément (https://www.opsian.com/blog/javas-new-zgc-is-very-exciting/).

ZGC fait son marquage en trois phases.

1. Courte phase d’arrêt du monde – Il examine les racines du GC, des variables locales qui pointent vers le reste du tas. Le nombre total de ces racines est généralement minime et n’évolue pas avec la taille de la charge, donc les pauses de ZGC sont très courtes et n’augmentent pas lorsque votre tas grandit.

2. Phase simultanée – Il parcourt le graphe d’objets et examine les pointeurs colorés, marquant les objets accessibles. La barrière de charge empêche la contention entre la phase GC et l’activité de toute application.

3. Phase de relocalisation – Elle déplace les objets vivants pour libérer de grandes sections du tas afin de rendre les allocations plus rapides. Lorsque la phase de relocalisation commence, ZGC divise le tas en pages et travaille sur une page à la fois. Une fois que ZGC a fini de déplacer toute racine, le reste de la relocalisation se produit dans une phase concurrente.

ZGC essaiera de définir lui-même le nombre de threads, et il a généralement raison. Mais si ZGC a trop de threads, il affamera votre application. S’il n’en a pas assez, vous créerez des déchets plus rapidement que le GC ne peut les collecter. Les phases de ZGC illustrent comment il gère les grands tas sans impacter les performances lorsque la mémoire de l’application augmente.

Pour activer Z Garbage Collector, nous pouvons utiliser l’argument suivant :

java -XX:+UseZGC -jar Application.java

Shenandoah

Shenandoah est un collecteur d’ordures à temps de pause ultra-faible qui réduit les temps de pause GC en effectuant plus de travail de collecte d’ordures simultanément avec le programme Java en cours d’exécution. CMS et G1 effectuent tous deux un marquage concurrent des objets vivants. Shenandoah ajoute la compaction concurrente.

Shenandoah utilise des régions de mémoire pour gérer les objets qui ne sont plus utilisés et ceux qui sont vivants et prêts pour la compression. Shenandoah ajoute également un pointeur de transfert à chaque objet du tas et l’utilise pour contrôler l’accès à l’objet. La conception de Shenandoah échange des cycles de CPU concurrents et de l’espace contre des améliorations du temps de pause. Le pointeur de transfert facilite le déplacement des objets, mais les déplacements agressifs signifient que Shenandoah utilise plus de mémoire et nécessite plus de travail parallèle que les autres GC. Mais il effectue le travail supplémentaire avec de très brèves pauses stop-the-world.

Shenandoah traite le tas en de nombreuses petites phases, dont la plupart sont concurrentes de l’application. Cette conception permet au GC de gérer efficacement un grand tas.

  1. Première pause stop-the-world du cycle. Elle prépare le tas pour le marquage concurrent et scanne l’ensemble des racines. CommeZGC, la longueur de cette pause correspond à la taille de l’ensemble racine, pas du tas.
  2. Puis, une phase concurrente parcourt le tas et identifie les objets atteignables et inatteignables.
  3. La troisième termine le processus de marquage en vidant les mises à jour du tas en attente et en balayant à nouveau l’ensemble racine. Cette phase déclenche la deuxième pause stop-the-world du cycle. Le nombre de mises à jour en attente et la taille de l’ensemble racine déterminent la durée de la pause.
  4. Puis, une autre phase simultanée copie les objets hors des régions identifiées dans la phase de marquage final. Ce processus distingue Shenandoah des autres GC car il compacte agressivement le tas en parallèle avec les threads d’application.
  5. La phase suivante déclenche la troisième (et la plus courte) pause du cycle. Elle permet de s’assurer que tous les threads du GC ont terminé l’évacuation.
  6. Quand elle se termine, une phase concurrente parcourt le tas et met à jour les références aux objets déplacés plus tôt dans le cycle.
  7. La dernière pause d’arrêt du cycle termine la mise à jour des références en mettant à jour l’ensemble de racines. En même temps, elle recycle les régions évacuées.
  8. Enfin, la dernière phase récupère les régions évacuées, qui n’ont maintenant aucune référence en elles.

Nous pouvons configurer Shenandoah avec l’une des trois heuristiques. Elles régissent le moment où le GC commence ses cycles et la façon dont il sélectionne les régions à évacuer.

1. Adaptative : Observe les cycles du GC et lance le cycle suivant de sorte qu’il se termine avant que l’application n’épuise le tas. Cette heuristique est le mode par défaut.

2. Statique : Démarre un cycle GC basé sur l’occupation du tas et la pression d’allocation.

3. Compact : Exécute des cycles GC en continu. Shenandoah démarre un nouveau cycle dès que le précédent se termine ou en fonction de la quantité de tas allouée depuis le dernier cycle. Cette heuristique entraîne une surcharge de débit mais fournit la meilleure récupération d’espace.

Shenandoah doit collecter le tas plus rapidement que l’application qu’il sert ne l’alloue. Si la pression d’allocation est trop élevée et qu’il n’y a pas assez d’espace pour les nouvelles allocations, il y aura un échec. Shenandoah dispose de mécanismes configurables pour cette situation.

  • Pacing : Si Shenandoah commence à prendre du retard sur le rythme d’allocation, il bloquera les fils d’allocation pour rattraper le retard. Les décrochages sont généralement suffisants pour de légers pics d’allocation. Shenandoah introduit des délais de 10 ms ou moins. Si le pacing échoue, Shenandoah passe à l’étape suivante : la GC dégénérée.
  • GC dégénérée : si un échec d’allocation se produit, Shenandoah commence une phase d’arrêt du monde. Il utilise cette phase pour terminer le cycle de GC actuel. Étant donné qu’un arrêt du monde ne se dispute pas les ressources avec l’application, le cycle devrait se terminer rapidement et combler le manque d’allocation. Souvent, un cycle dégénéré se produit après que la plupart du travail du cycle soit déjà terminé, donc l’arrêt du cycle est bref. Le journal GC le signalera cependant comme une pause complète.
  • GC complète : si le pacing et une GC dégénérée échouent tous deux, Shenandoah se rabat sur un cycle GC complet. Cette GC finale garantit que l’application n’échouera pas avec une erreur hors mémoire à moins qu’il n’y ait plus de tas.

Shenandoah offre les mêmes avantages que ZGC avec de grands tas mais plus d’options de réglage. Selon la nature de votre application, les différentes heuristiques peuvent être un bon ajustement. Ses temps de pause ne sont peut-être pas aussi brefs que ceux de ZGC, mais ils sont plus prévisibles.

Pour activer le collecteur d’ordures Shenandoah, nous pouvons utiliser l’argument suivant :

java -XX:+UseShenanodoahC -jar Application.java

Conclusion

L’objectif entier de cet article est de résumer tous les garbage collectors. Par conséquent, certaines parties du contenu ont été extraites des références données. Nous devons avoir une idée claire sur les garbage collectors afin de sélectionner un garbage collector optimal pour les cas d’utilisation de notre application. Le garbage collector optimal sera amélioré les performances de notre application de manière significative.

Référence

  1. https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
  2. https://www.baeldung.com/jvm-garbage-collectors
  3. https://dzone.com/articles/java-garbage-collection-3
  4. https://www.opsian.com/blog/javas-new-zgc-is-very-exciting/
  5. https://openjdk.java.net/projects/shenandoah/
  6. https://docs.oracle.com/en/java/javase/12/gctuning/z-garbage-collector1.html#GUID-A5A42691-095E-47BA-B6DC-FB4E5FAA43D0
  7. http://clojure-goes-fast.com/blog/shenandoah-in-production/

.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.