Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unloading a classloader

my final goal is to be able to reload classes after they have been already loaded to the JVM.

After reading the following answer Unloading classes in java? , I have been trying to implement my own Class-Loader, which itself creates a different instance of Class-Loader(same type of it's own) for each class it loads.

so, the outcome is one class per one Class-Loader.

The purpose is to be able to GC the class, meaning all of its instances, then to unload its class-loader , and to be able to reload the same class from its bytes.

the problem is - I can see my class instance being garbage collected using finalize() method, but I cant get my Class-Loader to unload, or to be garbage collected .
is there any code example, a simple test, that shows how it can be done?

thanks, any help would be appreciated

Edit:

to be clearer , i am interested in code examples where the instantiation of the new objects is via the 'new( )' operand, and the Class-loader isn't explicitly reloading the Class in the main, but after the next 'new( )' is called.

like image 315
eran levi Avatar asked Apr 30 '13 19:04

eran levi


People also ask

How do you unload a Java class?

There is no API in the Java platform for explicitly unloading a given class. Instead, "a class or interface may be unloaded if and only if its defining class loader may be reclaimed by the garbage collector" (JLS, chapter 12.7).

How do you close a Classloader?

In Java SE 7, the URLClassLoader close() method effectively invalidates the loader, so that no new classes can be loaded from it. It also closes any JAR files that were opened by the loader. This allows the application to delete or replace these files and, if necessary, create new loaders using new implementations.

What is class loading process?

The parent-delegation architecture to class loading was implemented to aid security and to help programmers to write custom class loaders. Class loading loads, verifies, prepares and resolves, and initializes a class from a Java class file. Loading involves obtaining the byte array representing the Java class file.

What is Classloader in JVM?

The Java ClassLoader is a part of the Java Runtime Environment that dynamically loads Java classes into the Java Virtual Machine. The Java run time system does not need to know about files and file systems because of classloaders. Java classes aren't loaded into memory all at once, but when required by an application.


1 Answers

The class loaders should be garbage collected if there are no more references to them. I took this code from @PeterLawrey (thanks) (it does the same thing as yours), put a log in the custom class loader finalize() method and voila, the class loaders are garbage collected after their loaded class is gc:

 /* 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.
 */


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

        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println(this.toString() + " - CL Finalized.");
        }
    }
}

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");
    }
}
like image 149
dcernahoschi Avatar answered Sep 21 '22 10:09

dcernahoschi