When and How Are Classes Garbage Collected in Java

When and how are classes garbage collected in Java?

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.

Java - which objects are being garbage collected?

Oracle's JFR (Java Flight Recorder, or Java Mission Control) is a great tool to help in this task - it shows the load on GC per object - meaning how many objects from each class are generated (this goes together with the objects that are collected). Very recommended.

Java garbage collector - When does it collect?

It runs when it determines that it is time to run. A common strategy in generational garbage collectors is to run the collector when an allocation of generation-0 memory fails. That is, every time you allocate a small block of memory (big blocks are typically placed directly into "older" generations), the system checks whether there's enough free space in the gen-0 heap, and if there isn't, it runs the GC to free up space for the allocation to succeed.
Old data is then moved to the gen-1 heap, and when space runs out there, the GC runs a collection on that, upgrading the data which has been there longest to the gen-2 heap, and so on. So the GC doesn't just "run". It might run on the gen-0 heap only (and most collections will do just that), or it might check every generation if it really has to free up a lot of memory (which is only necessary fairly rarely).

But this is far from the only strategy. A concurrent GC runs in the background, cleaning up while the program is running. Some GC's might run as part of every memory allocation. An incremental collector might do that, scanning a few objects at every memory allocation.

The entire point in a garbage collector is that it should just do its thing without requiring any input from the user. So in general, you can't, and shouldn't, predict when it'll run.

I believe Suns JVM gained a generational GC not too long ago (v1.6 maybe? I haven't coded Java for ages, so not sure on this, but I remember being surprised not too long ago, when one of the selling points for the new version was "a generational GC". Not least because .NET has had one since day 1.)

Other JVM's are of course free to pick whichever strategy they like.

EDIT: The above part about Java and generational GC is not true. See below for more details:

The 1.0 and 1.1 Virtual Machines used a mark-sweep collector, which could fragment the heap after a garbage collection. Starting with Java 1.2, the Virtual Machines switched to a generational collector, which has a much better defragmentation behavior (see Java theory and practice: Garbage collection and performance).

So Java actually has a generational GC for ages. What's new in Java 6 is the Garbage-First garbage collector (G1) that is available in Java 6u14. According to the article claiming the release in 1.6.0_14: It is not enabled by default. The parallel collector is still the default GC and is the most efficient GC for common household usage. G1 is meant to be an alternative for the concurrent collector. It is designed to be more predictable and enable fast allocation with memory regions design.

When will a string be garbage collected in java

Now in case of a string, this is not the case because string will go into the string pool and JVM will keep the object alive for reuse. So that means a string once created will 'never' be garbage collected?

First, it is only string literals (see notes) that get automatically interned / added to the string pool. String objects that are created by an application at runtime are not interned ... unless your application explicitly calls String.intern().

Second, in fact the rules for garbage collecting objects in the string pool are the same as for other String objects: indeed all objects. They will be garbage collected if the GC finds them to be unreachable.

In practice, the String objects that correspond to string literals typically do not become candidates for garbage collection. This is because there is an implicit reference to the String object in the code of every method that uses the literal. This means that the String is reachable for as long as the method could be executed.

However, this is not always the case. If a string literal was defined in a class that was dynamically loaded (e.g. using Class.forName(...)), then it is possible to arrange that the class is unloaded. If that happens, then the String object corresponding to the literal may then be unreachable, and may ultimately be GC'ed.

See also: When and how are classes garbage collected in Java?


Notes:

  1. A string literal (JLS 3.10.5) is a string that appears in Java source code; e.g.

      "abc"            // string literal
    new String(...) // not a string literal
  2. A string produced by evaluation of (compile-time) constant expression (JLS 15.28) may also be interned.

       "abc" + 123      // this is a constant expression
  3. Strictly speaking, not all String literals are interned:

    • If a String literal only appears in the source code as a sub-expression of a constant expression, then the literal may not appear in the ".class" file in any form. Such a literal won't be interned because it won't exist at runtime.

    • In Java 9+, string concatenations involving literals and values that are not compile time constants may be handled differently. Now, at the option of the bytecode compiler, a string concatenation like the following:

       int x = 42;   // not a compile time constant
      String s = "prefix " + x + " suffix";

      may result in a string constant like the following being interned:

       "prefix \1 suffix"

      At runtime, the above string constant is used as the "recipe" for generating a dynamic concatenation method. The original string literals (i.e. "prefix " and " suffix") would not turn into interned string objects.

      Kudos to @Holger for pointing this out. More details are in JEP 280 and the javadoc for StringConcatFactory.

  4. Prior to Java 7, the string pool was in PermGen. For some versions of Java, garbage collection of PermGen was not enabled by default if you selected the CMS collector. But CMS was never the default collector AND there was a flag to enable PermGen collection by CMS. (And nobody should be developing code for Java 6 and earlier anymore.)

When and how is a java classloader marked for garbage collection?

I always heard that Classloader unloading was problematic. They are theoretically garbage collected when there is not reference to the object instances and class unloading is not necessary, but in practice it seems like to be more problematic. Subtle references may leak and prevent the Classloader from being reclaimed. In application servers, after numerous redeploy cycle, I sometimes got a OutOfMemoryError: PermGen space.

All that to say that I guess there is a nasty reference somewhere that prevent it from being collected -- maybe the memory analyzer didn't followed the link correctly. It seems like all this can happen, as described in these articles:

  • Classloader leaks: the dreaded PermGen space exception
  • How to fix the dreaded PermGen space exception

Also, I don't know exactly what you are doing, but if you can wait for JDK 7, you could have a look at AnonymousClassLoader. They will be introduced to better support dynamic language, as explained in this post:

  • A first taste of InvokeDynamic

I hope it will help you.

Are non-static inner class objects garbage collected after they are no longer referenced?

Instances of the inner class will be garbage collected according to normal rules (i.e. when they are no longer referenced). However, each instance of the inner class contains a hidden reference to its parent instance of the outer class. This means that if there are any live references to instances of the inner class, they will prevent the associated instances of the outer class from being garbage collected. But it only works in that direction, not the other way around.

Are java.lang.Class objects ever garbage collected?

A java.lang.Class is tied to the class it represents. The garbage collection of the Class instance implies unloading the class, which is possible, but only under certain circumstances. For a normal class or interface, it requires not only the Class object but also its defining ClassLoader instance to become unreachable, which in turn requires all classes of this particular class loader to be unreachable.

That’s addressed in the specification in §12.7. Unloading of Classes and Interfaces:

An implementation of the Java programming language may unload classes.

A class or interface may be unloaded if and only if its defining class loader may be reclaimed by the garbage collector as discussed in §12.6.

Classes and interfaces loaded by the bootstrap loader may not be unloaded.

All Built-in Class Loaders will never become unreachable.

But there’s also the defineHiddenClass method which allows to define special, “hidden” classes which may get garbage collected even if their defining loader is reachable (unless the STRONG option has been specified).



Related Topics



Leave a reply



Submit