何时以及如何在Java中收集类垃圾?
我在本主题中询问了有关Java中垃圾收集的问题 。 但我得到的答案,给了我另一个问题。
有人提到垃圾收集器也可以收集类。 这是真的?
如果确实如此,这是如何工作的?
当没有引用它时,Java中的类可以被垃圾收集。 在大多数简单的设置中,这种情况永远不会发生,但在某些情况下可能会发生。
有很多方法可以使类可以访问,从而阻止它符合GC的条件:
- 该类的对象仍然可以访问。
- 表示类的
Class
对象仍然可以访问 - 加载类的
ClassLoader
仍然可以访问 -
ClassLoader
加载的其他类仍然可以访问
当这些都不成立时, ClassLoader
及其加载的所有类都符合GC的条件。
这是一个应该演示行为的构造示例(充满了不良做法!):
在目录(而不是包!) x
创建字节码文件GCTester.class
。 它的源代码是:
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"); } }
然后在x
的父目录中创建一个类TestMe
:
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
将生成此(或类似)输出:
在主要 创建ClassLoader 装载class级 获得静态领域 读取静态值 GCTester @ 1feed786创建 得到的价值:GCTester @ 1feed786 第一次gc()调用 第二次gc()调用(在main中) GCTester @ 1feed786敲定 主要结束
在倒数第二行,我们看到GCTester
实例已经完成,这只能意味着类(和ClassLoader
)符合垃圾回收的条件。