Java: Classes Instance et Immortel

 

Le code proposé est non déterministe. D'une exécution à l'autre, son résultat peut différer. L'explication est la suivante :
 
Le garbage collector est un processus géré exclusivement par la machine virtuelle. Il s'exécute en parallèle des différentes tâches en cours d'exécution.
 
L'appel à System.gc() ne provoque pas immédiatement (de manière préemptive) la suspension des tâches en cours et l'exécution du garbage collector. Il s'agit en réalité d'une requête faite à la machine virtuelle, et non pas d'un ordre. La documentation de cette méthode dans l'API l'indique clairement :
 
     Appeler la méthode gc suggère à la JVM d'intensifier son effort
     de recyclage des objets inutilisés afin de rendre rapidement
     disponible la mémoire qu'ils occupent.
     Quand l'appel de la méthode termine, la JVM a fait de son mieux
     pour récupérer l'espace rendu disponible par tous les objets
     éliminés.
 
Pour obtenir les traces d'exécutions indiquées, on peut essayer de donner un peu de temps à la machine virtuelle pour répondre à la requête System.gc(). Les versions suivantes introduisent un délai d'attente de 50ms après chaque appel à System.gc() :
 
class InstanceRalenti {
    static int nbInstances;
    static int cptInstance;
    int numInstance;
    static {
nbInstances = 0;
    }
    {
nbInstances++;
cptInstance++;
numInstance = cptInstance;
    }
    public void finalize(){
nbInstances--;
    }
    public String toString() {
return "("+numInstance+")";
    }
 
    public static void main(String[] args) throws Exception {
InstanceRalenti i1 = new InstanceRalenti();
InstanceRalenti i2 = new InstanceRalenti();
InstanceRalenti i3 = new InstanceRalenti();
System.out.println(i1+" "+i2+" "+i3+" total : "
  +nbInstances); // (1) (2) (3) total : 3
i2=i3;
System.gc();
Thread.sleep(50);
System.out.println(i1+" "+i2+" "+i3+" total : "
  +nbInstances); // (1) (3) (3) total : 2
i1=null;
System.gc();
Thread.sleep(50);
System.out.println(i1+" "+i2+" "+i3+" total : "
  +nbInstances); // null (3) (3) total : 1
    }
}
 
class ImmortelRalenti {
    static int nbInstances;
    static int cptInstance;
    static ImmortelRalenti zombie;
    int numInstance;
    static {
nbInstances = 0;
    }
    {
nbInstances++;
cptInstance++;
numInstance = cptInstance;
    }
    public void finalize(){
nbInstances--;
zombie=this;
    }
    public String toString() {
return "("+numInstance+")";
    }
 
    public static void main(String[] args) throws Exception {
ImmortelRalenti i1 = new ImmortelRalenti();
ImmortelRalenti i2 = new ImmortelRalenti();
ImmortelRalenti i3 = new ImmortelRalenti();
System.out.println(i1+" "+i2+" "+i3+" total : "
  +nbInstances+" | "
  +zombie); // (1) (2) (3) total : 3 | null
i2=i3;
System.gc();
Thread.sleep(50);
System.out.println(i1+" "+i2+" "+i3+" total : "
  +nbInstances+" | "
  +zombie); // (1) (3) (3) total : 2 | (2)
i1=null;
System.gc();
Thread.sleep(50);
System.out.println(i1+" "+i2+" "+i3+" total : "
  +nbInstances+" | "
  +zombie); // null (3) (3) total : 1 | (1)
zombie = null;
System.gc();
Thread.sleep(50);
System.out.println(i1+" "+i2+" "+i3+" total : "
  +nbInstances+" | "
  +zombie); // null (3) (3) total : 1 | null
    }
}