A class in Java can be garbage-collected when nothing references it. In most simple setups this never happens, but there are situations where it can occur.
There are many ways to make a class reachable and thus prevent it from being eligible for GC:
- objects of that class are still reachable.
- the
Class
object representing the class is still reachable
- the
ClassLoader
that loaded the class is still reachable
- other classes loaded by the
ClassLoader
are still reachable
When none of those are true, then the ClassLoader
and all classes it loaded are eligible for GC.
Here's a constructed example (full of bad practices!) that should demonstrate the behaviour:
Create a bytecode file GCTester.class
in a directory (not package!) x
. It's source code is:
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");
}
}
Then create a class TestMe
in the parent directory of 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);
}
}
Running TestMe
will produce this (or similar) output:
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
In the second to last line we see that the GCTester
instance is finalized, which can only mean that the class (and ClassLoader
) are eligible for garbage collection.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…