Garbage collector en Java

Libération de mémoire

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

Pour les développeurs issus du monde PHP la notion d'une ramasse-miettes peut paraître abstraite. Cependant en Java elle est très importante pour garantir une meilleure performance de l'application.

Cette ramasse-miettes s’appelle en réalité garbage collector (GC). C'est un Thread deamon qui tourne d'une manière transparente. Il analyse l'utilisation des objets. Si un objet n'est plus utilisé (aucun autre objet lui fait référence), il est considéré par GC comme libérable. Cet objet est alors supprimé de la mémoire. Grâce à ce mécanisme, l'application évite beaucoup de problèmes liés à des fuites de mémoire.

Les objectifs du garbage collector peuvent se résumer à :

  1. s'assurer que les objets vivants (ceux qui sont toujours référencés) ne seront pas supprimés
  2. récupérer la mémoire des objets morts
  3. allouer de l'espace à de nouveaux objets
  4. compacter la mémoire

Comment déterminer si un objet est libérable ?

Garbage collector détermine tout seul si l'objet peut être supprimé de la mémoire. Comme mentionné, il vérifie si d'autres objets lui font référence. Si ce n'est pas le cas, il devient éligible à la libération. Cependant, cela ne fonctionne pas dans la situation d'interdépendance. Si l'objet 1 fait référence à l'objet 2 et inversement, les deux sont libérables.

Quel est le cycle de vie des objets en Java ?

Les objets en Java sont traités en fonction de leur age. Grâce à cette information ils peuvent être classés dans la "génération" correspondante. L'arborescence des génération par défaut se présente ainsi : - young (jeune) : composé des trois parties : eden, survivor 1 et survivor 2. Chaque nouvelle instance est placée dans la partie eden. Ensuite, au fil du temps, elle est analysé par le garbage collector. S'il s'aperçoit qu'elle est vivante, il la déplace vers un espace survivor. Chaque fois une partie du survivor doit être libre pour pouvoir accueillir de nouveaux objets. Si un objet est suffisamment ancien, il est déplacé dans la génération tenured. - tenured (durée de vie plus longue) : les objets y sont placés suite à un nombre de passages du GC précis. Par exemple, on a détermine que le GC doit vérifier un objet 10 fois. Si au bout du 10e fois l'objet sera toujours vivant (il y aura d'autres objets qui y feront référence), il sera placé dans la génération tenured. - permanent (permanente) : ici on retrouve les objets qui seront vivants tout au long du cycle de vie d'une application. Il s'agit d'objets qui ne pourront jamais être réclamés par le garbage collector. On y retrouve les méthodes des classes, les noms des classes, des constantes.

Le garbage collector traverse l'application en analysant les objets y présent. Cette action s’appelle marking (marquage). Chaque objet que le GC croise dans cette file est marqué en tant qu'utilisé. Il n'est pas traité comme supprimable lors de l'étape suivante, appelée sweeping. Lors de cette étape, le compactage de la mémoire se produit (les objets inutiles sont transférés et l'espace vide apparaît; cet espace est alors compacté par le rapprochement des objets toujours vivants).

Méthode finalize()

Java exécute donc les opérations de libération de mémoire toute seule. Cependant, le développeur possède une possibilité de spécifier l'action qui doit s'exécuter avant cette opération automatique. Il s'agit ici de la méthode protected void finalize(). Regardons cela sur l'exemple d'un simple code :

afficher le code

Les deux endroits sont cruciaux. Le premier est la suppression de référence à l'objet Destructor (d = null). Tout de suite au-dessous on remarque l'appel d'une méthode statique de la classe System, gc(). Elle évoque directement le passage du garbage collector. Sur l'écran on verra le résultat :

Objet is finalized

Néanmois, il n'y a pas de garantie que la méthode finalize() sera appelée par le GC. Il ne faut pas non plus abuser avec l'appel manuel du garbage collector. Voici les raisons qui refroidissent les développeurs avant l'utilisation de cette fonction :

  1. Le fonctionnement du garbage collector est automatique. Il possède des paramètres configurables, mais la fréquence des appels devrait être gérée par la JVM. L'évocation manuelle peut provoquer des problèmes avec les performances de l'application.
  2. L'appel manuel du garbage collector ne garantit pas son exécution.
  3. L'exécution manuelle de la méthode System.gc() ne doit pas forcément être plus efficace qu'automatique. En fait elle est moins utile quand il y a peu d'objets dans la file qui risquent d'être traitées inefficacement. Il vaut donc mieux laisser à la JVM de gérer la fréquence des appels.
  4. L'évocation manuelle du System.gc(), même très fréquente, n'empêchera pas l'application de provoquer une exception OutOfMemory. Le garbage collector va essayer de libérer de l'espace. Malgré cela l'extrême peut tout de même être atteint.
  5. L'appel de la méthode finalize() n'est pas garanti par la JVM.
télécharger les fichiers d'exemple

Une question ? Une remarque ?

*

*

Un conseil CSS

Si vous rencontrez un problème lors de l'utilisation du filtre de transparence pour IE6.

La définition qui permet d'utiliser la transparence sous IE6 pour la classe textFooter se présente ainsi :

.textFooter { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', src='/images/bottom.png', sizingMethod='scale'); background: none; }

Cependant, il se peut qu'elle ne fonctionne pas correctement. Dans ce cas-là, commencez à la débugger par l'ajout du nom de domaine dans l'attribut src. On obtiendrait alors :
.textFooter { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', src='http://mysite.com/images/bottom.png', sizingMethod='scale'); background: none; }