Votre application tourne peut-être avec un autre GC que celui que vous croyez.

En Java 25, G1 est le garbage collector par défaut. Mais la JVM en propose d’autres, chacun pour un besoin. Et sur une petite machine, elle en choisit un autre toute seule.

Les GC disponibles en Java 25

GCCe qu’en dit le guide d’OracleOption
SerialUn seul thread pour tout le travail du GC. Pour un petit jeu de données (jusqu’à 100 Mo environ) ou un seul processeur-XX:+UseSerialGC
ParallelLe « throughput collector » : comme Serial, mais avec plusieurs threads. Si la performance brute compte le plus, et que des pauses d’une seconde ou plus sont acceptables-XX:+UseParallelGC
G1Un GC « en grande partie concurrent » : il fait une partie du travail pendant que l’application tourne. Si le temps de réponse compte plus que le débit-XX:+UseG1GC
ZGCDes pauses de moins d’une milliseconde, au prix d’un peu de débit. Si la latence est la priorité-XX:+UseZGC
ShenandoahUn GC à pauses courtes, lui aussi. Le guide d’Oracle n’en parle pas ; il fonctionne avec Temurin 25-XX:+UseShenandoahGC

Et un cas à part : Epsilon. Il alloue la mémoire, mais ne la libère jamais. Quand le heap est plein, la JVM s’arrête. Il sert pour des tests (mesurer une application sans GC, vérifier qu’un test ne crée pas trop d’objets) ou des tâches très courtes. En Java 25, il est encore expérimental : il faut -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC.

Le GC par défaut : G1… sauf sur une petite machine

La JVM choisit G1 sur une machine « server-class » : au moins deux processeurs et au moins 1792 Mo de mémoire physique. Sinon, elle choisit Serial.

Sur une machine de développement, c’est presque toujours G1. Mais dans un petit conteneur limité à un seul CPU, la JVM passe à Serial, sans rien dire. Le comportement de l’application peut alors changer entre le poste du développeur et la production.

Le conseil du guide d’Oracle : sauf si vous avez des contraintes de pause strictes, lancez d’abord l’application et laissez la JVM choisir.

Comment savoir quel GC tourne

Au démarrage, avec -Xlog:gc, la JVM l’écrit dès la première ligne :

[0.015s][info][gc] Using G1

Sans lancer l’application, -XX:+PrintFlagsFinal montre le choix de la JVM pour cette machine (ergonomic veut dire « choisi par la JVM ») :

     bool UseG1GC                                  = true                                      {product} {ergonomic}

Et pour une application déjà lancée, jcmd <pid> VM.flags affiche ses options, avec par exemple -XX:+UseG1GC.

Ce qui a changé

Frise des garbage collectors de Java 8 à Java 25 : G1 par défaut en Java 9, CMS supprimé en Java 14, ZGC et Shenandoah en production en Java 15, puis leurs modes générationnelsLes GC de Java 8 à Java 25Java 8Parallel par défautPermGen → MetaspaceJava 9G1 par défautCMS dépréciéJava 11ZGC, Epsilon(expérimentaux)Java 12Shenandoah(expérimental)Java 14CMS suppriméJava 15ZGC, Shenandoahen productionJava 21ZGC générationnel(option)Java 23ZGC générationnelpar défautJava 24ZGC : seulementgénérationnelJava 25Shenandoahgénérationnel stable
Ce qu’on lit encoreCe qui est vrai aujourd’huiDepuis
Parallel est le GC par défautG1 est le GC par défautJava 9
CMS, le GC à faibles pausesCMS est supprimé. En Java 17, 21 et 25, -XX:+UseConcMarkSweepGC empêche même la JVM de démarrerDéprécié en Java 9, supprimé en Java 14
ZGC et Shenandoah sont expérimentauxIls sont prêts pour la productionJava 15
ZGC n’a pas de générationsZGC est générationnel, et c’est le seul mode depuis Java 24Java 21 à 24
Shenandoah n’a pas de générationsSon mode générationnel est stable en Java 25, mais ce n’est pas le mode par défaut (-XX:ShenandoahGCMode=generational)Java 25

Sources : le guide d’Oracle sur le garbage collector (JDK 25), JEP 248 (G1 par défaut), JEP 291 et JEP 363 (CMS), JEP 377 (ZGC), JEP 379 et JEP 521 (Shenandoah), JEP 318 (Epsilon).

En résumé

G1 est le bon point de départ, et c’est celui que la JVM choisit sur une machine normale. ZGC et Shenandoah visent les pauses les plus courtes, Parallel le débit, Serial les petites machines. Avant de changer de GC, vérifiez lequel tourne vraiment, surtout dans un conteneur.

Pour aller plus loin