何时以及如何在Java中收集类垃圾?

Jor*_*ust 27 java garbage-collection class

我在本主题中询问了有关Java中垃圾收集的问题.但我得到的答案,给了我另一个问题.

有人提到垃圾收集器也可以收集类.这是真的?

如果是真的,这是如何工作的?

Joa*_*uer 31

当没有任何引用它时,Java中的类可以被垃圾收集.在大多数简单的设置中,这种情况永远不会发生,但有些情况可能会发生.

有很多方法可以使类可以访问,从而阻止它符合GC的条件:

  • 该类的对象仍然可以访问.
  • 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");
  }
}
Run Code Online (Sandbox Code Playgroud)

然后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);
  }
}
Run Code Online (Sandbox Code Playgroud)

运行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)符合垃圾回收的条件.

  • @Joachim Sauer:调用*finalize()*的事实只证明你的对象进入"无法访问"状态,而不是它已被GCed.GC仍可随意收集或不收集:已调用finalize这一事实并不意味着该对象已被GCed.如果要跟踪它是否已经过GCed,则需要将PhantomReference放在ReferenceQueue上并在该队列上进行轮询.然后,无论如何,即使你证明该对象确实已经被GCed,这只会使它的类和类加载器(在你的例子中)符合GC的条件,而不是自动GCed. (10认同)