Notes sur les "finaliseurs"



Qu'est ce qu'un finaliseur ?


En JAVA, lorsqu'une instance de classe cesse d'etre accessible la garbage collector restitue automatiquement au systeme la memoire utilisee par l'instance.

En C++ ce n'est pas le cas. Les instances sont crees avec l'operateur new (comme en JAVA). Par contre si l'instance cesse d'etre referencee, la memoire qui lui est allouee n'est pas automatiquement restituee au systeme. Si l'on n'y prend garde la memoire "perdue" s'accumule (c'est ce que l'on nomme "une fuite de memoire") et l'application (ou le systeme) fini par "planter".

C'est pourquoi en C++ tout objet intancie dynamiquement doit etre explicitement detruit (grace a l'operateur delete). Les destructeurs (methode automatiquement axecutee lors de la destruction d'une instance) en C++ jouent un role tres important car ils permettent de proceder a toutes les operations de restitution de memoire lors de la destruction d'une instance.

L'utilite du garbage collector de JAVA peut etre discutee: elle comporte des avantages et des inconvenients.

Mais revenons au finaliseur. Lors de la destruction d'une instance, JAVA execute automatiquement la methode finalize(). Il suffit de redefinir cette methode pour effectuer toutes les operations necessaires lors de la destruction d'une instance.

Exemple

Considerons l'exemple suivant:

Fichier test.java
public class test
{
  public static void main (String[] atgv)
  {
    int j = 0;

    while (true) { new finaliseur(j++); };
  }
}

class finaliseur
{
  int n;

  finaliseur(int val)
  {
    System.out.println("Creation d'une instance de la classe finaliseur."+ val);
    n = val;
  }
  
  public void finalize()
  {
    System.out.println("Destruction d'une instance de la classe finalize - "+ n);
  }
}


Voici une partie de l'affichage obtenu lors de l'execution du programme:

...
Creation d'une instance de la classe finaliseur.52
Creation d'une instance de la classe finaliseur.53
Creation d'une instance de la classe finaliseur.54
Creation d'une instance de la classe finaliseur.55
Creation d'une instance de la classe finaliseur.56
Creation d'une instance de la classe finaliseur.57
Creation d'une instance de la classe finaliseur.58
Creation d'une instance de la classe finaliseur.59
Creation d'une instance de la classe finaliseur.60
...
Creation d'une instance de la classe finaliseur.2474
Destruction d'une instance de la classe finalize - 151
Creation d'une instance de la classe finaliseur.2475
Destruction d'une instance de la classe finalize - 152
Creation d'une instance de la classe finaliseur.2476
Destruction d'une instance de la classe finalize - 153
Creation d'une instance de la classe finaliseur.2477
Destruction d'une instance de la classe finalize - 154
Creation d'une instance de la classe finaliseur.2478
...


Le programme cree des instances de la classe finaliseur. Tant que la memoire disponible est suffisante, le garbage collector ne fait rien (premiere partie de l'affichage). Par contre lorsque la memoire devient insuffisante, le garbage collector detruit des instances de la classes finaliseur (seconde partie de l'affichage).

Peut on controler l'action du garbage collector ?

Pour detruire explicitement la reference vers une instance (et ainsi la rendre eligible pour la destruction lors de la prochaine activation du garbage collector) il suffit d'attribuer la valeur null au handle referencant l'instance.

exemple:
Fichier test.java
public class test
{
  public static void main (String[] atgv)
  {
    finaliseur fin = new finaliseur();
    fin = null;
  }
}

class finaliseur
{
  finaliseur()
  {
    System.out.println("Creation d'une instance de la classe finaliseur.");
  }
  
  public void finalize()
  {
    System.out.println("Destruction d'une instance de la classe finalize - ");
  }
}

Toutes les versions de JAVA disponibles presentent un garbage collector. Cependant il faut savoir que ce n'est pas une obligation. Le garbage collector ne fait pas partie de la norme officielle.

Par consequent il faut considerer chaque implementation du garbage collector comme possedant ses propres particularites (ses subtilites). Un controle fin de l'action du garbage collector est donc illusoire dans une optique de developpement multi-systeme (l'un des avanteges pretendus de JAVA).

Toutefois ils existent des moyens "d'influencer" l'action du garbage collector. On peut citer (la liste n'est pas exhaustive):
  • les SoftReference.
  • les WeakReference.
  • les PhantomReference.
  • la methode java.lang.System.gc().
  • la methode java.lang.System.runFinalization();


SoftReference, WeakReference et PhantomReference s'appliquent aux handles. Ces attributs determinent la facon dont les instances sont "manipulees" par le garbage collector.

La methode gc() permet d'activer explicitement le garbage collector. Attention: cela ne signifie pas que toutes les instances non referencees seront automatiquement detruites. Une fois acuive le garbage collector determine s'il y a lieu de detruire des instances.

La methode runFinalization() provoque la destruction des instances collectees par le garbage collector. Le garbage collector travaille en deux temps: losrque le garbage collector est active il detruit les instances collectees lors de sa precedente activation, puis il collecte (si il y a lieu) d'autres instances qui seront detruites lors de la prochaine activetion.