何时以及如何在Java中对类进行垃圾回收?

2022-09-01 12:03:04

本主题中,我问了一个关于 Java 中的垃圾回收的问题。但是我得到的答案,给了我另一个问题。

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

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


答案 1

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

有许多方法可以使课程可访问,从而阻止其有资格获得GC:

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

如果这些不成立,则它加载的类和所有类都有资格获得 GC。ClassLoader

下面是一个构造的示例(充满了不良做法!),应该可以证明这种行为:

在目录中创建字节码文件(不是包! 。它的源代码是:GCTester.classx

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

然后在的父目录中创建一个类:TestMex

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

在倒数第二行中,我们看到实例已最终确定,这只能表示类(和 )符合垃圾回收的条件。GCTesterClassLoader


答案 2