Когда и как классы собирают мусор в Java? - PullRequest
26 голосов
/ 12 марта 2010

Я задал вопрос о сборке мусора на Java в этой теме . Но ответ, который я получил, дал мне другой вопрос.

Кто-то упомянул, что классы также могут быть собраны сборщиком мусора. Это правда?

А если это правда, как это работает?

1 Ответ

31 голосов
/ 12 марта 2010

Класс в Java можно собирать, когда на него ничего не ссылается. В большинстве простых установок этого никогда не происходит, но бывают ситуации, когда это может произойти.

Есть много способов сделать класс достижимым и, таким образом, лишить его права на GC: * ​​1003 *

  • объекты этого класса все еще доступны.
  • объект Class, представляющий класс, все еще доступен
  • ClassLoader, который загрузил класс, все еще доступен
  • другие классы, загруженные ClassLoader, все еще доступны

Когда нет из этих истинных, тогда ClassLoader и все загруженные им классы имеют право на GC.

Вот составленный пример (полный плохой практики!), Который должен продемонстрировать поведение:

Создать файл байт-кода GCTester.class в каталоге (не в пакете!) x. Это исходный код:

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

Затем создайте класс TestMe в родительском каталоге 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);
  }
}

Запуск TestMe выдаст этот (или аналогичный) вывод:

in main
Creating ClassLoader
Loading Class
Getting static field
Reading static value
GCTester@1feed786 created
Got value: GCTester@1feed786
First gc() call
Second gc() call (in main)
GCTester@1feed786 finalized
End of main

От второй до последней строки мы видим, что экземпляр GCTester завершен, что может означать только то, что класс (и ClassLoader) имеют право на сборку мусора.

...