Sur le garbage collector Java, on trouve beaucoup d’articles, et beaucoup sont anciens : PermGen, CMS, -XX:+PrintGCDetails… Ce guide résume ce qui est vrai en Java 25, en quelques lignes par sujet. Chaque partie renvoie à un article plus complet, où chaque fait est vérifié dans la documentation officielle ou sur une vraie JVM.

Je mets ce guide à jour quand la série avance, ou quand une nouvelle version de Java change les règles.

La mémoire de la JVM

La JVM range ses données dans plusieurs zones :

  • la stack : une par thread, avec une frame par appel de méthode (paramètres, variables locales). Elle se libère toute seule, sans le GC. Trop d’appels empilés donnent un StackOverflowError ;
  • le heap : les objets créés avec new, partagés par tous les threads. C’est la zone du garbage collector. Sa taille maximale se règle avec -Xmx ;
  • le Metaspace : la description des classes, en mémoire native, hors du heap. Il a remplacé PermGen en Java 8.

La JVM utilise aussi de la mémoire native pour les stacks des threads, le code compilé par le JIT, les buffers directs et ses structures internes. -Xmx ne limite que le heap : le processus Java utilise toujours plus.

→ La mémoire de la JVM : Heap, Stack, Metaspace

Générations et cycles

La plupart des objets meurent jeunes. La JVM range donc les objets récents dans la Young (l’Eden et deux Survivor) et ceux qui durent dans la Old :

Le trajet d'un objet dans le heap : il naît dans l'Eden, passe d'un Survivor à l'autre à chaque minor collection, puis il est promu dans la OldHeapYoungles objets récentsEdenles objets naissent iciobjetSurvivor 0les deux Survivor serventSurvivor 1à tour de rôle ; un est videOldles objets qui durentobjet1231Minor collection : l'objet vivant est copié de l'Eden vers un Survivor.2À chaque minor collection, il passe dans l'autre Survivor ; son âge augmente.3Après assez de copies (MaxTenuringThreshold, 15 par défaut) : promu dans la Old.

Un objet naît dans l’Eden, passe d’un Survivor à l’autre à chaque GC, puis il est promu dans la Old après un certain nombre de copies (15 au maximum par défaut).

Dans le guide d’Oracle, une minor collection ne nettoie que la Young, et une major collection nettoie tout le heap. G1, le GC par défaut, n’utilise pas ces mots dans ses logs : il parle de pauses Young, Mixed et Full. Et depuis Java 9, il découpe le heap en régions de même taille, au lieu de deux grands blocs.

→ Générations et cycles de GC : Young, Old, Minor, Major, Full

Les garbage collectors

Java 25 propose plusieurs GC, chacun pour un besoin :

  • G1, le GC par défaut depuis Java 9 : quand le temps de réponse compte plus que le débit ;
  • ZGC et Shenandoah : des pauses très courtes, pour la latence ;
  • Parallel : le débit avant tout ;
  • Serial : un seul thread, pour les petites machines ;
  • Epsilon : ne libère jamais rien, pour des tests.

CMS n’existe plus depuis Java 14. Attention aussi au choix automatique : sur une machine avec un seul processeur ou moins de 1792 Mo de mémoire, la JVM prend Serial au lieu de G1. Un petit conteneur peut donc tourner avec un autre GC que le poste du développeur. Pour le vérifier : -Xlog:gc écrit le GC utilisé dès la première ligne (Using G1).

→ Les garbage collectors Java en 2026 : lequel tourne chez vous ?

Les options utiles

Quelques options suffisent dans la plupart des cas :

  • -Xms et -Xmx : la taille initiale et maximale du heap, souvent la même valeur sur un serveur ;
  • -Xlog:gc*:file=gc.log : les logs du GC dans un fichier, avec une rotation déjà intégrée ;
  • -XX:+HeapDumpOnOutOfMemoryError et -XX:HeapDumpPath : un dump du heap quand il est plein ;
  • -XX:MaxRAMPercentage : le heap maximum en pourcentage de la mémoire (25 % par défaut), utile dans un conteneur.

Beaucoup d’anciennes options ne marchent plus. Certaines sont seulement dépréciées (-XX:+PrintGCDetails, -Xloggc), mais d’autres empêchent la JVM de démarrer en Java 17, 21 et 25 : -XX:MaxPermSize, -XX:+UseConcMarkSweepGC, -XX:+PrintGCDateStamps… Pour tester une configuration, il suffit de lancer java <options> -version.

→ Les options JVM qui comptent, et celles qui ne marchent plus

Les idées reçues

  • System.gc() n’est qu’une demande. Mais avec G1, Parallel et Serial, elle déclenche en général un Full GC, qui coûte cher.
  • finalize() est dépréciée et prévue pour suppression : à la place, try-with-resources ou Cleaner.
  • Plus de heap aide souvent, tant qu’il tient dans la mémoire de la machine ou du conteneur.
  • Régler le GC n’est pas la première chose à faire : G1 avec ses réglages par défaut, puis les logs, puis l’application.
  • Le GC n’empêche pas les fuites mémoire : un objet encore référencé n’est jamais libéré.

→ Idées reçues sur le garbage collector Java

FAQ

Quelle différence entre le heap et la stack ?

La stack appartient à un thread : elle contient les variables locales et se vide quand la méthode se termine. Le heap est partagé par tous les threads : il contient les objets, et c’est le GC qui le nettoie. Une variable locale de type objet est dans la stack, mais l’objet lui-même est dans le heap.

Quel est le GC par défaut en Java 25 ?

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

Peut-on forcer le GC ?

Non. System.gc() est une demande, sans garantie. Avec G1, Parallel et Serial, elle donne en général un Full GC. Avec -XX:+DisableExplicitGC, la JVM ignore ces appels.

Pourquoi mon application se fige quelques instants ?

Les pauses du GC sont une cause possible, pas la seule. Pour le savoir, regardez les logs du GC (-Xlog:gc*) : chaque pause y est écrite avec sa durée. Avec G1, un Pause Full qui ne vient pas de System.gc() est le signe d’un heap trop plein, et la doc prévient qu’il peut être très lent. Des Full GC qui se répètent indiquent un heap trop petit ou une fuite mémoire.

Quel GC pour une application Spring Boot ?

Spring Boot ne choisit pas le GC : c’est la JVM, avec les mêmes règles que pour toute application Java. Une application Spring Boot 3.5 sur Java 25 démarre avec G1, et avec Serial si la JVM ne voit qu’un seul processeur. Commencez avec G1 et ses réglages par défaut, et vérifiez le GC utilisé avec -Xlog:gc.

La suite de la série

Ce guide couvre les bases. La suite de la série ira plus loin :

Ces articles seront ajoutés à ce guide au fur et à mesure.