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.
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).
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.
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.
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.
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");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With