我的最终目标是能够在已经加载到JVM之后重新加载类。
在阅读了以下答案Unloading classes in java?之后,我一直在尝试实现自己的类加载器,它本身为它加载的每个类创建一个不同的类加载器实例(它自己的类型)。
所以,结果是每个Class-Loader一个类。
目的是能够GC类,意味着它的所有实例,然后卸载它的类加载器,并能够从其字节重新加载相同的类。
问题是 - 我可以看到我的类实例使用finalize()方法进行垃圾收集,但是我无法卸载Class-Loader,或者被垃圾收集。 是否有任何代码示例,一个简单的测试,显示它是如何完成的?
谢谢,任何帮助将不胜感激
修改:
更清楚,我对代码示例感兴趣,其中新对象的实例化是通过'new()'操作数,而类加载器没有显式地重新加载主类中的Class,但是在下一个'new()'被调用之后。
答案 0 :(得分:10)
如果没有更多的引用,则应该对类加载器进行垃圾回收。我从@PeterLawrey中获取this code(谢谢)(它与你的相同),在自定义类加载器finalize()
方法中添加一个日志,然后,类加载器在加载类后被垃圾收集是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");
}
}
答案 1 :(得分:1)
在 IBM J9 VM 中,由于类加载器仅在全局gc期间卸载,因此情况有所不同。这会导致全局gc中的暂停时间过长,并且当存在大量gc时会导致内存不足
正在创建的类加载器。我在JMXMP中遇到了这个问题,其中为com.sun.jmx.remote.opt.util.OrderClassLoaders
类型的每个远程消息创建了一个MBeanServerRequestMessage.CREATE_MBEAN_LOADER_PARAMS
类加载器实例。