When and how are classes garbage collected in Java?
Asked Answered
E

1

31

I asked a question about Garbage Collection in Java in this topic. But the answer I got, gave me another question.

Someone mentioned that classes can be collected by the garbage collector too. Is this true?

And if it is true, how does this work?

Eyeless answered 12/3, 2010 at 14:15 Comment(2)
You may find this topic helpful: #453523Tumpline
This one as well: "When and how is a java classloader marked for garbage collection?" #2345464Primordium
R
37

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.

Rheotropism answered 12/3, 2010 at 14:20 Comment(4)
@Joachim Sauer: The fact that finalize() is called only proves in that case that your object moves into the "unreachable" state, not that it has been GCed. The GC is still free to collect it or not, at its will: the fact that finalize has been called does not mean that the object has been GCed. If you want to track if it has been GCed you need to put a PhantomReference on a ReferenceQueue and poll on that queue. And then anyway, even should you prove that the object has really been GCed, this only makes its class and classloader (in your example), eligible for GC, not automatically GCed.Laevogyrate
@Wizard: true enough, I should have said "that it's eligible for GC".Rheotropism
@JoachimSauer, You stated 4 conditions (the 4 points) that will prevent a Class from being eligible for GC. Now, even when we have cleared the 4 hurdles, is it still possible that the system doesn't collect the Class? Basically, I'm asking is the JLS saying a JVM should release non-referenced Class or is it saying a JVM must-eventually release a non-referenced Class?Cabman
@Pacerier: that's a good question, and I don't know the answer for sure. My guess would be that it acts the same way as normal garbage collection: it will eventually be garbage collected but could just as well not do it.Rheotropism

© 2022 - 2024 — McMap. All rights reserved.