2010-03-12 5 views
25

J'ai posé une question à propos de Garbage Collection en Java dans this topic. Mais la réponse que j'ai reçue m'a donné une autre question.Quand et comment les classes sont-elles collectées en Java?

Quelqu'un a mentionné que les classes peuvent également être collectées par le garbage collector. Est-ce vrai?

Et si c'est vrai, comment cela fonctionne-t-il?

+3

Vous pouvez trouver ce sujet utile: http://stackoverflow.com/questions/453023/are-static-fields-open-for-garbage-collection –

+1

Celui-ci aussi: "Quand et comment un classloader java est marqué pour la collecte des ordures? " http://stackoverflow.com/questions/2344964/when-and-how-is-a-java-classloader-marked-for-garbage-collection – ewernli

Répondre

29

Une classe en Java peut être collectée sans que rien ne la mentionne. Dans la plupart des configurations simples, cela n'arrive jamais, mais il y a des situations où cela peut se produire.

Il y a plusieurs façons de faire une classe accessible et empêcher ainsi d'être admissible à GC:

  • objets de cette classe sont encore accessibles.
  • l'objet Class représentant la classe est toujours accessible
  • le ClassLoader qui a chargé la classe est toujours accessible
  • autres classes chargées par le ClassLoader sont encore accessibles

Lorsque aucun de ceux sont vraies , puis ClassLoader et toutes les classes chargées sont éligibles pour GC.

Voici un exemple construit qui doit démontrer le comportement (plein de mauvaises pratiques!):

Créer un fichier bytecode GCTester.class dans un répertoire (paquet pas!) x. Il est le code source est:

public class GCTester { 
    public static final GCTester INSTANCE=new GCTester(); 

    private GCTester() { 
    System.out.println(this + " created"); 
    } 

    public void finalize() { 
    System.out.println(this + " finalized"); 
    } 
} 

Ensuite, créez une classe TestMe dans le répertoire parent de x:

import java.io.File; 
import java.net.URL; 
import java.net.URLClassLoader; 
import java.lang.reflect.Field; 

public class TestMe { 
    public static void main(String[] args) throws Exception { 
    System.out.println("in main"); 
    testGetObject(); 
    System.out.println("Second gc() call (in main)"); 
    System.gc(); 
    Thread.sleep(1000); 
    System.out.println("End of main"); 
    } 

    public static void testGetObject() throws Exception { 
    System.out.println("Creating ClassLoader"); 
    ClassLoader cl = new URLClassLoader(new URL[] {new File("./x").toURI().toURL()}); 
    System.out.println("Loading Class"); 
    Class<?> clazz = cl.loadClass("GCTester"); 

    System.out.println("Getting static field"); 
    Field field = clazz.getField("INSTANCE"); 

    System.out.println("Reading static value"); 
    Object object = field.get(null); 
    System.out.println("Got value: " + object); 

    System.out.println("First gc() call"); 
    System.gc(); 
    Thread.sleep(1000); 
    } 
} 

L'exécution TestMe produira ce (ou similaire) Sortie:

 
in main 
Creating ClassLoader 
Loading Class 
Getting static field 
Reading static value 
[email protected] created 
Got value: [email protected] 
First gc() call 
Second gc() call (in main) 
[email protected] finalized 
End of main 

En la deuxième à la dernière ligne, nous voyons que l'instance GCTester est finalisée, ce qui peut seulement signifier que la classe (et ClassLoader) sont éligibles pour la collecte des ordures.

+9

@Joachim Sauer: Le fait que * finalize() * soit appelé ne prouve que dans ce cas, votre objet passe à l'état "inaccessible", pas qu'il ait été GCed. Le GC est toujours libre de le collecter ou non, à sa guise: le fait que la finalisation ait été appelée ne signifie pas que l'objet a été GCé. Si vous voulez suivre si elle a été GCed vous devez mettre un PhantomReference sur un ReferenceQueue et interroger sur cette file d'attente. Et puis de toute façon, même si vous prouvez que l'objet a vraiment été GCed, cela ne fait que rendre sa classe et son classloader (dans votre exemple), éligible pour GC, pas automatiquement GCed. – SyntaxT3rr0r

+0

@Wizard: assez vrai, j'aurais dû dire "que c'est éligible pour GC". –

+0

@JoachimSauer, Vous avez déclaré 4 conditions (les 4 points) qui empêcheront une 'Classe' d'être éligible pour GC. Maintenant, même lorsque nous avons franchi les 4 obstacles, est-il toujours possible que le système ne collecte pas la 'Classe'? Fondamentalement, je demande à la JLS de dire qu'une JVM * devrait * publier une 'Class' non référencée ou est-ce qu'elle dit qu'une JVM * doit - ** finalement *** publier une' Class' non référencée? – Pacerier

Questions connexes