Retour

Vendredi 24 mai 2024

Gestion de la mémoire en Java

Comme vous le savez sûrement, le Java est un langage de haut niveau et il dispose de fonctionnalités de gestion automatique de la mémoire. Mais comment est-elle gérée ? C’est ce que nous allons voir dans cet article.   © iStock/adventtr   Tout d’abord, il faut savoir que l’application Java ne s’exécute pas directement dans le système d’exploitation, mais au sein d’une machine virtuelle qu’on appelle la JVM (Java Virtual Machine). C’est elle qui permet de gérer la mémoire grâce au ramasse-miettes ou garbage collector.  

Quel est le rôle du ramasse-miettes ?

  Son rôle est de libérer la mémoire des objets qui ne sont plus utilisés, c’est-à-dire lorsqu’il n’existe plus de référence qui pointe vers cet objet dans la JVM. Il s’exécute dans un ou plusieurs threads de la JVM. Son algorithme consiste basiquement à parcourir l’espace mémoire et à marquer les objets toujours utilisés. La mémoire sera alors récupérée sur les objets non marqués. Le temps d’exécution est donc proportionnel au nombre d’objets contenus dans la mémoire, ce qui peut avoir un impact sur la performance de l’application puisque les autres traitements sont stoppés durant l’exécution du ramasse-miettes. On appelle d’ailleurs ce traitement la phase « Stop the world ». Afin de pallier ce problème, le fonctionnement du ramasse-miettes s’appuie principalement sur deux concepts.  

1. Différentes zones de stockage mémoire dans la JVM :

  Au lancement de l’application, le système alloue de la mémoire à la JVM, on appelle cet espace mémoire la Heap. Elle est organisée en plusieurs zones :  
  • La Young Generation: Elle se divise en trois parties. La première que l’on nomme Eden et qui stocke les objets nouvellement créés. Les deux autres que l’on appelle Survivor car elles contiennent les objets qui ont survécu à une opération de libération de la mémoire au sein de la Young Generation (la collection mineure).
  • La Old Generation: Après avoir survécu à plusieurs collections mineures, les objets sont stockés dans la Old Generation. Une collection majeure est lancée seulement en cas de manque de mémoire dans cet espace.
  • La Permanent Generation : Ici sont stockées les données nécessaires au bon fonctionnement du programme.
 

2. Différents algorithmes proposés à utiliser selon les besoins

 
  • Le Serial Garbage Collector : Il s’agit de l’implémentation la plus simple. Il fonctionne sur un seul thread en mode « Stop the world »
    • Recommandé pour les applications clientes qui nécessitent peu de mémoire.
  • Le Parallel Garbage Collector: Une implémentation qui utilise plusieurs threads pour paralléliser les traitements et qui fonctionne également en mode « Stop the world »
    • Recommandé pour profiter de machines avec plusieurs CPU.
  • Le CMS Garbage Collector : L’implémentation Concurrent Mark Sweep utilise plusieurs threads pour marquer ( « Mark » ) et supprimer ( « Sweep » ) les objets inutilisés simultanément. Les autres traitements ne sont pas stoppés pendant la phase de nettoyage.
  • Le Garbage-First Collector : Cette implémentation permet d’exécuter la phase de « Mark » simultanément sur plusieurs sections de la Heap.
  Nous allons terminer cet article sur les options que vous pouvez facilement configurer pour améliorer les performances de la JVM :
  • -Xms = <T> : définition de la taille minimum de la Heap lors du démarrage de la JVM,
  • -Xmx = <T> : définition de la taille maximum que peut atteindre la Heap lors de l’exécution.
D’autres options permettent également de configurer les tailles des différents espaces de la Heap.  

En conclusion

Le garbage collector est un gain de temps pour les développeurs qui n’ont plus à se soucier de la gestion de la mémoire en codant leurs applications. Cependant, il est intéressant de comprendre les concepts derrière ce traitement afin de configurer le garbage collector et la JVM pour optimiser les performances.  

Elodie