Java 卸载类加载器
我的最终目标是能够在类已经加载到JVM之后重新加载它们 在阅读了下面的答案之后,我一直在尝试实现我自己的类加载器,它本身为它加载的每个类创建一个不同的类加载器实例(它自己的相同类型) 因此,结果是每个类装入器一个类 这样做的目的是能够GC类,也就是它的所有实例,然后卸载它的类加载器,并且能够从它的字节中重新加载相同的类 问题是-我可以看到我的类实例正在使用finalize()方法进行垃圾收集,但我无法让我的类加载器卸载或进行垃圾收集。Java 卸载类加载器,java,garbage-collection,classloader,Java,Garbage Collection,Classloader,我的最终目标是能够在类已经加载到JVM之后重新加载它们 在阅读了下面的答案之后,我一直在尝试实现我自己的类加载器,它本身为它加载的每个类创建一个不同的类加载器实例(它自己的相同类型) 因此,结果是每个类装入器一个类 这样做的目的是能够GC类,也就是它的所有实例,然后卸载它的类加载器,并且能够从它的字节中重新加载相同的类 问题是-我可以看到我的类实例正在使用finalize()方法进行垃圾收集,但我无法让我的类加载器卸载或进行垃圾收集。 是否有任何代码示例,一个简单的测试,来说明如何实现它 谢谢,
是否有任何代码示例,一个简单的测试,来说明如何实现它 谢谢,任何帮助都将不胜感激 编辑:
更清楚地说,我对代码示例感兴趣,其中新对象的实例化是通过“new()”操作数进行的,并且类装入器没有在main中显式地重新装入类,而是在调用下一个“new()”之后。如果没有更多的引用,则应该对类装入器进行垃圾收集。我从@PeterLawrey(谢谢)(它做的事情和你的一样),在自定义类加载器
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");
}
}
/*版权所有(c)2011。彼得·劳瑞
*
*“啤酒用具许可证”(第128版)
*只要你保留这个通知,你可以用它做任何你想做的事情。
*如果有一天我们见面,你觉得这些东西值得,你可以给我买杯啤酒作为回报
*没有担保。
*/
导入java.lang.reflect.Field;
导入java.net.URL;
导入java.net.URLClassLoader;
公共类LoadAndUnloadMain{
publicstaticvoidmain(String…args)抛出ClassNotFoundException、NoSuchFieldException、IllegalAccessException、interruptedeexception{
URL URL=LoadAndUnloadMain.class.getProtectionDomain().getCodeSource().getLocation();
最后一个字符串className=LoadAndUnloadMain.class.getPackage().getName()+“.UtilityClass”;
{
类加载器cl;
课堂讨论;
对于(int i=0;i<2;i++){
cl=新CustomClassLoader(url);
clazz=cl.loadClass(类名);
载荷等级(clazz);
cl=新CustomClassLoader(url);
clazz=cl.loadClass(类名);
载荷等级(clazz);
triggerGC();
}
}
triggerGC();
}
私有静态void triggerGC()引发InterruptedException{
System.out.println(“\n——启动GC”);
gc();
睡眠(100);
System.out.println(“--GC结尾\n”);
}
私有静态void loadClass(Class clazz)抛出NoSuchFieldException、IllegalAccessException{
最终字段id=clazz.getDeclaredField(“id”);
id.setAccessible(true);
id.get(null);
}
私有静态类CustomClassLoader扩展了URLClassLoader{
公共CustomClassLoader(URL){
超级(新URL[]{URL},空);
}
@凌驾
受保护类loadClass(字符串名称,布尔解析)引发ClassNotFoundException{
试一试{
返回super.loadClass(名称、解析);
}catch(classnotfounde异常){
返回Class.forName(name、resolve、LoadAndUnloadMain.Class.getClassLoader());
}
}
@凌驾
受保护的void finalize()抛出可丢弃的{
super.finalize();
System.out.println(this.toString()+“-CL定稿”);
}
}
}
类实用类{
静态最终字符串ID=Integer.toHexString(System.identityHashCode(UtilityClass.class));
私有静态最终对象final=新对象(){
@凌驾
受保护的void finalize()抛出可丢弃的{
super.finalize();
System.out.println(ID+“Finalized.”);
}
};
静止的{
System.out.println(ID+“初始化”);
}
}
在IBMJ9VM中,情况有所不同,因为类加载器卸载只在全局gc期间发生。这可能会导致全局gc中出现大量暂停时间,并在存在大量数据时导致内存不足
正在创建的类加载器。我在JMXMP中遇到了这个问题,其中为类型为
MBeanServerRequestMessage.CREATE_MBEAN_LOADER_PARAMS
的每个远程消息创建了com.sun.jmx.remote.opt.util.OrderClassLoaders
classloader的一个实例 谢谢,我对通过“new()”操作数显示类实例的代码示例更感兴趣,很抱歉我的问题不清楚,我将对其进行编辑。当您通过自定义ClassLoader
加载类时,您将得到一个class
对象。不可能将新的
运算符与此一起使用。使用new
意味着您的代码已链接到new
使用的类,因此,当包含new
表达式的代码仍处于活动状态时,该类无法被垃圾收集。此时必须使用反射,例如在类上调用newInstance()
。当然,动态加载的代码本身可以使用new
在其自己的范围内实例化类。