Table of Contents
Overview
- Static fields live on the heap, can have any number of copies and are cleaned up by the GC like any other object.
- Loading multiple copies of a static field:
- Each class loader which loads a class has its own copy of static fields.
- If you load a class in two different class loaders these classes can have static fields with different values.
- Unloading static fields
- Static fields are unloaded when the Class’ ClassLoader is unloaded.
- This is unloaded when a GC is performed and there are no strong references from the threads’ stacks.
Note this article is a 100% copy of Peter Lawrey article :
Java Code Details
How the code works: In this log, two copies of the class are loaded first. The references to the first class/classloader are overwritten by references to the second class/classloader. The first one is cleaned up on a GC, the second one is retained. On the second loop, two more copies are initialised. The forth one is retained, the second and third are cleaned up on a GC. Finally the forth copy of the static fields are cleaned up on a GC when they are no longer references. Java Code LoadAndUnloadMain.java Copyright (c) 2011. Peter Lawrey * * "THE BEER-WARE LICENSE" (Revision 128) * As long as you retain this notice you can do whatever you want with this stuff. * If we meet some day, and you think this stuff is worth it, you can buy me a beer in return * There is no warranty. */ package test; import java.lang.reflect.Field; import java.net.URL; import java.net.URLClassLoader; public class LoadAndUnloadMain { public static void main(String... args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InterruptedException { URL url = LoadAndUnloadMain.class.getProtectionDomain().getCodeSource().getLocation(); final String className = LoadAndUnloadMain.class.getPackage().getName() + ".UtilityClass"; { ClassLoader cl; Class clazz; for (int i = 0; i < 2; i++) { cl = new CustomClassLoader(url); clazz = cl.loadClass(className); loadClass(clazz); cl = new CustomClassLoader(url); clazz = cl.loadClass(className); loadClass(clazz); triggerGC(); } } triggerGC(); } private static void triggerGC() throws InterruptedException { System.out.println("\n-- Starting GC"); System.gc(); Thread.sleep(100); System.out.println("-- End of GC\n"); } private static void loadClass(Class clazz) throws NoSuchFieldException, IllegalAccessException { final Field id = clazz.getDeclaredField("ID"); id.setAccessible(true); id.get(null); } private static class CustomClassLoader extends URLClassLoader { public CustomClassLoader(URL url) { super(new URL[]{url}, null); } @Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { try { return super.loadClass(name, resolve); } catch (ClassNotFoundException e) { return Class.forName(name, resolve, LoadAndUnloadMain.class.getClassLoader()); } } } } class UtilityClass { static final String ID = Integer.toHexString(System.identityHashCode(UtilityClass.class)); private static final Object FINAL = new Object() { @Override protected void finalize() throws Throwable { super.finalize(); System.out.println(ID + " Finalized."); } }; static { System.out.println(ID + " Initialising"); } }
Compile and run the code
[oracle@wls1 CLASSLoader_and_GC]$ javac test/LoadAndUnloadMain.java [oracle@wls1 CLASSLoader_and_GC]$ java test.LoadAndUnloadMain 5552bb15 Initialising 456d3d51 Initialising -- Starting GC 5552bb15 Finalized. -- End of GC 302b2c81 Initialising 2b1be57f Initialising -- Starting GC 302b2c81 Finalized. 456d3d51 Finalized. -- End of GC -- Starting GC 2b1be57f Finalized. -- End of GC