【问题标题】:When and how are classes garbage collected in Java?Java 中何时以及如何收集类垃圾?
【发布时间】:2011-01-26 20:33:59
【问题描述】:

我在this topic 中问了一个关于 Java 垃圾收集的问题。 但我得到的答案,给了我另一个问题。

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

如果这是真的,这是怎么回事?

【问题讨论】:

标签: java garbage-collection class


【解决方案1】:

Java 中的类可以在没有任何引用的情况下被垃圾回收。在大多数简单的设置中,这永远不会发生,但在某些情况下可能会发生。

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

  • 该类的对象仍然可以访问。
  • 表示该类的 Class 对象仍然可以访问
  • 加载类的ClassLoader仍然可以访问
  • ClassLoader 加载的其他类仍然可以访问

当 none 为真时,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 将产生这个(或类似的)输出:

主要是 创建类加载器 加载类 获取静态字段 读取静态值 GCTester@1feed786 已创建 得到值:GCTester@1feed786 第一次 gc() 调用 第二次 gc() 调用(在 main 中) GCTester@1feed786 定稿 主线结束

在倒数第二行中,我们看到GCTester 实例已完成,这只能意味着该类(和ClassLoader)有资格进行垃圾回收。

【讨论】:

  • @Joachim Sauer:调用 finalize() 的事实仅证明在这种情况下您的对象进入“无法访问”状态,而不是它已被 GC。 GC 仍然可以随意收集或不收集它:finalize 已被调用这一事实并不意味着该对象已被 GC。如果要跟踪它是否已被 GC,则需要在 ReferenceQueue 上放置一个 PhantomReference 并在该队列上轮询。然后无论如何,即使您证明该对象确实已被 GC,这只会使其类和类加载器(在您的示例中)符合 GC,而不是自动 GC。
  • @Wizard:真的,我应该说“它有资格获得 GC”。
  • @JoachimSauer,您陈述了 4 个条件(即 4 点),这将阻止 Class 有资格获得 GC。现在,即使我们已经清除了 4 个障碍,系统是否仍有可能没有收集到Class?基本上,我要问的是 JLS 是说 JVM 应该 释放未引用的Class 还是说 JVM 必须-最终发布一个未引用的Class?
  • @Pacerier:这是个好问题,但我不确定答案。我的猜测是它的行为方式与普通垃圾收集相同:它最终会被垃圾收集,但也可以不这样做。
猜你喜欢
  • 2023-03-19
  • 2020-01-25
  • 2010-10-09
  • 2010-12-13
  • 2016-08-16
  • 2014-06-02
  • 1970-01-01
  • 1970-01-01
  • 2011-02-25
相关资源
最近更新 更多