Garbage Collector en Java

Maintenant que nous avons manipulé nos objets, il est temps de les ranger. Heureusement, la JVM s’en charge pour nous. Java fournit un ramasse-miettes (garbage collector Java) qui recherche automatiquement les objets qui ne sont plus nécessaires.

Il est important de noter que votre code n’est pas le seul processus qui s’exécute dans votre programme Java. Le code Java existe à l’intérieur d’une JVM, qui comprend de nombreux processus indépendants de votre code d’application. L’un des plus importants est le ramasse-miettes intégré.

Comprendre le Tas (Heap) en Java

Tous les objets Java sont stockés dans le tas (heap) de la mémoire de votre programme. Le tas, également appelé “free store”, représente une grande réserve de mémoire non utilisée allouée à votre application Java. Si votre programme continue à instancier des objets et à les laisser dans le tas, il finira par manquer de mémoire et planter. Mais pas de panique ! Le garbage collector résout ce problème.

Comprendre le Garbage Collector

Le garbage collector fait référence au processus de libération automatique de la mémoire sur le tas en supprimant les objets qui ne sont plus accessibles dans votre programme. Il existe de nombreux algorithmes différents pour le garbage collector.

En tant que développeur, l’aspect le plus intéressant du garbage collector est de déterminer quand la mémoire appartenant à un objet peut être récupérée. En Java et dans d’autres langages, “éligible au garbage collector” fait référence à l’état d’un objet qui n’est plus accessible dans un programme et peut donc être nettoyé.

Est-ce qu’un objet éligible au garbage collector sera immédiatement nettoyé ? Absolument pas. Le moment où l’objet est effectivement supprimé n’est pas sous votre contrôle.

Pensez à l’éligibilité au garbage collector comme à l’envoi d’un colis. Vous pouvez prendre un article, le mettre dans une boîte étiquetée et le déposer dans votre boîte aux lettres. C’est analogue à rendre un élément éligible au garbage collector. Quand le facteur viendra le chercher, ce n’est pas sous votre contrôle. Par exemple, ce pourrait être un jour férié, ou il pourrait y avoir des intempéries. Vous pouvez même appeler la poste et leur demander de venir le chercher immédiatement, mais il n’y a aucun moyen de garantir quand et si cela se produira réellement.

Java inclut une méthode intégrée pour aider à la gestion du garbage collector, où vous pouvez suggérer son exécution :

System.gc();

Tout comme la poste, Java est libre de vous ignorer. Cette méthode n’est pas garantie de faire quoi que ce soit.

Tracer l’Éligibilité au Garbage Collector

Comment la JVM sait-elle quand un objet est éligible au garbage collector ? La JVM surveille patiemment chaque objet jusqu’à ce qu’elle détermine que le code n’a plus besoin de cette mémoire. Un objet restera dans le tas jusqu’à ce qu’il ne soit plus accessible. Un objet n’est plus accessible dans deux situations :

  • L’objet n’a plus aucune référence qui pointe vers lui
  • Toutes les références vers l’objet sont sorties de portée

Objets vs Références

Ne confondez pas une référence avec l’objet qu’elle référence ; ce sont deux entités différentes. La référence est une variable qui a un nom et peut être utilisée pour accéder au contenu d’un objet. Une référence peut être assignée à une autre référence, passée à une méthode ou retournée par une méthode. Toutes les références ont la même taille, quel que soit leur type.

Concept de base du Garbage Collection Java: une référence pointant vers un objet dans le tas

Un objet réside dans le tas et n’a pas de nom. Par conséquent, vous n’avez aucun moyen d’accéder à un objet sauf à travers une référence. Les objets ont des formes et des tailles différentes et consomment des quantités variables de mémoire. Un objet ne peut pas être assigné à un autre objet, et un objet ne peut pas être passé à une méthode ou retourné par une méthode. C’est l’objet qui est collecté par le garbage collector, pas sa référence.

Prenons un exemple concret pour bien comprendre. Regardez ce code et essayez de déterminer quand chaque objet devient éligible au garbage collector :

public class Portee {
    public static void main(String[] args) {
        String un, deux;
        un = new String("a");
        deux = new String("b");
        un = deux;
        String trois = un;
        un = null;
    }
}

Prenez un crayon et du papier. Nous allons tracer ensemble ce qui se passe. Vraiment, prenez le temps de le faire, c’est important pour bien comprendre.

Analysons pas à pas

1. À la ligne 3, écrivez ‘un’ et ‘deux’ (juste les mots – pas besoin de boîtes ou de flèches puisqu’aucun objet n’est encore dans le tas).

Java: deux références non initialisée

2. À la ligne 4, nous avons notre premier objet. Dessinez une boîte avec la chaîne “a”, et tracez une flèche du mot ‘un’ vers cette boîte.

Garbage Collector Java: Une des deux références 'un' pointent vers son objets respectifs 'a'

3. La ligne 5 est similaire. Dessinez une autre boîte avec la chaîne “b” et une flèche du mot ‘deux’.

Java: deux références 'un' et 'deux' pointent vers leurs objets respectifs 'a' et 'b'

4. À la ligne 6, la variable ‘un’ change pour pointer vers “b”. Effacez ou barrez la flèche de ‘un’ et dessinez une nouvelle flèche de ‘un’ vers “b”.

Java: deux références 'un' et 'deux' pointent vers l'objet 'b'

5. À la ligne 7, nous avons une nouvelle variable, alors écrivez le mot ‘trois’ et dessinez une flèche de ‘trois’ vers “b”. Notez que ‘trois’ pointe vers ce que ‘un’ pointe actuellement et non vers ce qu’il pointait au début.

Garbage Collector Java: trois références vers l'objet 'b', l'objet 'a' devient éligible au nettoyage

6. Enfin, barrez la ligne entre ‘un’ et “b” puisque la ligne 8 définit cette variable à null.

Garbage Collector Java: référence 'un' nulle, 'deux' et 'trois' pointent vers 'b', 'a' prêt au nettoyage

Conclusion sur l’éligibilité au garbage collector

Reprenons maintenant quand les objets deviennent éligibles au garbage collector :

  • À la ligne 6, nous avons supprimé la seule flèche pointant vers “a”, rendant cet objet éligible au garbage collector.
  • “b” a des flèches qui pointent vers lui jusqu’à ce qu’il sorte de portée à la fin de la méthode.

Cette approche visuelle de traçage des références est un excellent moyen de comprendre comment la mémoire est gérée en Java. En visualisant les connexions entre les références et les objets, vous pouvez facilement déterminer quand un objet devient éligible pour le garbage collector.

Si vous avez besoin de plus de contrôle sur votre garbage collector, plus d’informations sont disponibles dans cet article Oracle.

https://docs.oracle.com/en/java/javase/17/gctuning/introduction-garbage-collection-tuning.html

Quizz

Quelles affirmations concernant le programme suivant sont correctes ? (Choisissez toutes les réponses qui s’appliquent.)


public class Ours {
    private Ours pandaOurs;
    private void rugir(Ours o) {
        System.out.println("Roar!");
        pandaOurs = o;
    }
    public static void main(String[] args) {
        Ours oursBrun = new Ours();
        Ours oursPolaire = new Ours();
        oursBrun.rugir(oursPolaire);
        oursPolaire = null;
        oursBrun = null;
        System.gc();
    }
}
  • A. L’objet créé à la ligne 9 devient éligible au garbage collection après la ligne 13.
  • B. L’objet créé à la ligne 9 devient éligible au garbage collection après la ligne 14.
  • C. L’objet créé à la ligne 10 devient éligible au garbage collection après la ligne 12.
  • D. L’objet créé à la ligne 10 devient éligible au garbage collection après la ligne 13.
  • E. L’exécution du garbage collection est garantie.
  • F. Le garbage collection peut ou peut ne pas s’exécuter.
  • G. Le code ne compile pas.

Parmi les affirmations suivantes concernant le garbage collection, lesquelles sont correctes ? (Choisissez toutes les réponses qui s’appliquent.)

  • A. L’appel à System.gc() garantit la libération de mémoire en détruisant les objets éligibles au garbage collection.
  • B. Le garbage collection s’exécute selon un planning défini.
  • C. Le garbage collection permet à la JVM de récupérer de la mémoire pour d’autres objets.
  • D. Le garbage collection s’exécute quand votre programme a utilisé la moitié de la mémoire disponible.
  • E. Un objet peut être éligible au garbage collection mais ne jamais être supprimé du tas.
  • F. Un objet devient éligible au garbage collection dès qu’aucune référence vers lui n’est accessible dans le programme.
  • G. Marquer une variable comme final signifie que l’objet associé ne sera jamais collecté par le garbage collector.
Voir les réponses

Question 1 – Réponses A, D, F: Décortiquons ce qui se passe avec nos objets Ours !

Pour l’objet créé à la ligne 9 (notre oursBrun) :

  • Il reste vivant jusqu’à la ligne 13, où sa dernière référence disparaît. C’est là qu’il devient éligible au nettoyage ! (A vrai)

Pour l’objet créé à la ligne 10 (notre oursPolaire) :

  • Même si on met oursPolaire à null à la ligne 12, notre objet est toujours accessible via oursBrun.pandaOurs
  • Il ne devient orphelin qu’à la ligne 13, quand oursBrun disparaît (D vrai)

Et n’oubliez pas : System.gc() est juste une suggestion au garbage collector. C’est comme demander gentiment à quelqu’un de passer l’aspirateur – il peut le faire tout de suite, plus tard, ou pas du tout ! (F vrai)


Question 2 – Réponses C, E, F: Voici les points essentiels à retenir sur le garbage collection :

✅ Son but ? Récupérer la mémoire pour vos autres objets (C vrai) ✅ Un objet peut être “prêt à être nettoyé” mais rester dans le tas – comme un carton marqué “à jeter” qui reste dans votre garage (E vrai) ✅ Un objet devient éligible dès que vous ne pouvez plus l’atteindre dans votre code – comme un objet que vous ne pouvez plus toucher ni voir (F vrai)

Les autres idées sont des mythes ! Le garbage collector n’a pas d’horaire fixe, ne s’active pas à 50% de mémoire utilisée, et marquer une variable final ne protège pas son objet du nettoyage.