2010-03-12 8 views
25

Hice una pregunta sobre la recolección de basura en Java en this topic. Pero la respuesta que obtuve me dio otra pregunta.¿Cuándo y cómo se recolectan las clases de basura en Java?

Alguien mencionó que las clases también pueden ser recolectadas por el recolector de basura. ¿Es esto verdad?

Y si es cierto, ¿cómo funciona esto?

+3

Puede resultar útil este tema: http://stackoverflow.com/questions/453023/are-static-fields-open-for-garbage-collection –

+1

Éste también: "Cuándo y cómo se marca un cargador de clases java para la recolección de basura? " http://stackoverflow.com/questions/2344964/when-and-how-is-a-java-classloader-marked-for-garbage-collection – ewernli

Respuesta

29

Una clase en Java se puede recolectar basura cuando nada hace referencia a ella. En la mayoría de las configuraciones simples, esto nunca sucede, pero hay situaciones en las que puede ocurrir.

Hay muchas maneras de hacer una clase accesible y así evitar que sea elegible para GC:

  • objetos de esa clase son todavía accesibles.
  • el objeto Class que representa la clase es todavía alcanzable
  • la ClassLoader que carga la clase es todavía alcanzable
  • otras clases cargadas por el ClassLoader son todavía alcanzable

Cuando ninguno de los que son verdaderas , entonces el ClassLoader y todas las clases que cargó son elegibles para GC.

Aquí está un ejemplo de construcción que deben demostrar el comportamiento (lleno de malas prácticas!):

Crear un archivo de código de bytes GCTester.class en un directorio (no paquete!) x. Es el código fuente es:

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"); 
    } 
} 

A continuación, cree una clase TestMe en el directorio padre 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); 
    } 
} 

Correr TestMe producirá este (o similar) de salida:

 
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 penúltima línea vemos que la instancia GCTester está finalizada, lo que solo puede significar que la clase (y)) son elegibles para la recolección de basura.

+9

@Joachim Sauer: El hecho de que * finalize() * se llame solo demuestra en ese caso, su objeto se mueve al estado "inalcanzable", no es que haya sido GCed. El GC todavía puede recogerlo o no, a su voluntad: el hecho de que se haya llamado a finalización no significa que el objeto haya sido GCed. Si desea rastrear si ha sido GCed, necesita poner PhantomReference en una ReferenceQueue y sondear en esa cola. Y de todos modos, incluso si compruebas que el objeto realmente ha sido GCed, esto solo hace que su clase y su cargador de clases (en tu ejemplo), sean elegibles para GC, no sean GCed automáticamente. – SyntaxT3rr0r

+0

@Wizard: es cierto, debería haber dicho "que es elegible para GC". –

+0

@ JoachimSauer, indicó 4 condiciones (los 4 puntos) que evitarán que una 'Clase 'sea elegible para GC. Ahora, incluso cuando hemos despejado los 4 obstáculos, ¿todavía es posible que el sistema no recolecte la 'Clase '? Básicamente, estoy preguntando si JLS dice que una JVM * debe * liberar una 'Clase' no referenciada o si dice que una JVM * debe - ** eventualmente *** lanzar una 'Clase' no referenciada? – Pacerier

Cuestiones relacionadas