Quando e como as classs são coletadas em Java?

Eu fiz uma pergunta sobre o Garbage Collection em Java neste tópico . Mas a resposta que recebi me deu outra pergunta.

Alguém mencionou que as classs também podem ser coletadas pelo coletor de lixo. Isso é verdade?

E se é verdade, como isso funciona?

Uma class em Java pode ser coletada como lixo quando nada faz referência a ela. Na maioria das configurações simples, isso nunca acontece, mas há situações em que isso pode ocorrer.

Há muitas maneiras de tornar uma class acessível e, assim, impedir que ela seja elegível para GC:

  • objects dessa class ainda são alcançáveis.
  • o object Class representando a class ainda está acessível
  • o ClassLoader que carregou a class ainda está acessível
  • outras classs carregadas pelo ClassLoader ainda podem ser acessadas

Quando nenhuma delas é verdadeira, o ClassLoader e todas as classs carregadas são elegíveis para o GC.

Aqui está um exemplo construído (cheio de más práticas!) Que deve demonstrar o comportamento:

Crie um arquivo de bytecode GCTester.class em um diretório (não pacote!) x Seu código fonte é:

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

Em seguida, crie uma class TestMe no diretório pai 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); } } 

A execução do TestMe produzirá essa saída (ou similar):

 no principal
 Criando o ClassLoader
 Classe de carregamento
 Obtendo campo estático
 Lendo o valor estático
 GCTester @ 1feed786 criado
 Tem valor: GCTester @ 1feed786
 Primeira chamada gc ()
 Segunda chamada gc () (na principal)
 GCTester @ 1feed786 finalizado
 Fim do principal

Na segunda até a última linha, vemos que a instância do GCTester está finalizada, o que pode significar apenas que a class (e o ClassLoader ) são elegíveis para garbage collection.