java 类加载器卸载,【深入明白Java虚拟机 】类加载器的命名空间以及类的卸载...

类加载器的命名空间

每个类加载器又有一个命名空间,由其以及其父加载器组成

类加载器的命名空间的作用和影响

每个类加载器又有一个命名空间,由其以及其父加载器组成

在每个类加载器自己的命名空间中不能泛起相同类名的类 (此处值得是类的全名,包罗包名)

在差别的类命名空间中,可能会泛起多个相同的类名的类

如下面的代码示例中, 首先界说一个类加载器 MyClassLoader

static class MyClassLoader extends ClassLoader {

private String classLoaderName;

private String classPath;

public MyClassLoader(String classPath, String classLoaderName) {

super(); // 未指定则默认使用应用类加载器

this.classLoaderName = classLoaderName;

this.classPath = classPath;

}

public MyClassLoader(ClassLoader parent, String classLoaderName) {

super(parent); // 显式的指定父类加载器

this.classLoaderName = classLoaderName;

}

@Override

protected Class> findClass(String name) {

System.out.println("MyClassLoader.findClass");

byte[] bytes = null;

try {

bytes = loadClassByte(name);

return defineClass(name, bytes, 0, bytes.length);

} catch (Exception e) {

throw new RuntimeException(e);

}

}

private byte[] loadClassByte(String name) throws Exception {

name = name.replace(".", "/");

File file = new File(this.classPath + name + ".class");

try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream();

InputStream fileStream = new FileInputStream(file)) {

int ch;

while ((ch = fileStream.read()) != -1) {

byteStream.write(ch);

}

return byteStream.toByteArray();

}

}

}

下面我们实验使用此类加载加载一个磁盘的class文件,代码如下:

public static void main(String[] args) throws ClassNotFoundException {

MyClassLoader classLoader = new MyClassLoader("/tmp/", "CustomClassLoader");

Class> aClass = classLoader.loadClass("com.zhoutao.classload.ReferenceExample004");

ClassLoader loader = aClass.getClassLoader();

System.out.println(loader);

System.out.println("----------------------");

MyClassLoader classLoader2 = new MyClassLoader("/tmp/", "CustomClassLoader");

Class> aClass2 = classLoader2.loadClass("com.zhoutao.classload.ReferenceExample004");

ClassLoader loader2 = aClass2.getClassLoader();

System.out.println(loader);

}

根据之前的理论,由于 ReferenceExample004 类在classLoader 中已经被加载,那么在 classLoader2 中将不会被加载,我们看一下输出的效果

MyClassLoader.findClass

com.zhoutao.classload.ReferenceExample010$MyClassLoader@610455d6

----------------------

MyClassLoader.findClass

com.zhoutao.classload.ReferenceExample010$MyClassLoader@60e53b93

总结

可以看到,类加载器的findClass(String) 方式被执行了两次,这是由于加载该类的类加载器是两个差别的工具,在文章的开头提及:每个类加载器又有一个命名空间,由其以及其父加载器组成 上面的两个类加载器显然命名空间不一致,以是findClass() 方式会被执行两次

类的卸载

在内存中的 Class 类没有引用的时刻就会被 JVM 卸载,由于 JVM 自带的类加载 启动类加载器,拓展类加载器以及应用类加载器,在三个类加载的实例一直被 JVM 引用,以是JVM 自带的类加载器加载的类一直被其加载器引用,以是不会被卸载。

然则自界说的类加载器的实例可以被手动的设置为null,这导致类加载不再被引用,其所加载的 class 类在没有实例其没有类加载器引用的情况下就会被卸载,卸载的时间发生在系统垃圾接纳的时刻。

类的卸载测试

同类的加载一样,要考察到类的卸载,可以通过添加 JVM 参数-XX:+TraceClassUnloading 的方式输入类的卸载信息。

public static void main(String[] args) throws ClassNotFoundException, InterruptedException {

MyClassLoader classLoader = new MyClassLoader("/tmp/", "CustomClassLoader");

Class> aClass = classLoader.loadClass("com.zhoutao.classload.ReferenceExample004");

classLoader = null;

aClass = null;

// 手动触发GC 考察类接纳的信息

System.gc();

TimeUnit.SECONDS.sleep(10);

}

通过控制台可以考察到类的卸载纪录:

MyClassLoader.findClass

[Unloading class com.zhoutao.classload.ReferenceExample004 0x00000007c0061028]

或者通过JVisual 工具考察到类的卸载历程, 为了便于考察,适当加长 延时的时间 TimeUnit.SECONDS.sleep(100);, 终端或者CMD终端 输入 jvisualvm 下令启动,启动测试程序,在 jvisualvm 工具中接连到该线程,可以看到下面的信息:

已卸载的总数为: 1

7e32f7d9c4d8f9234d2af102b6368483.png

迎接关注微信民众号获取更多开发技巧干货

原文链接:https://www.cnblogs.com/zhoutao825638/p/12394088.html

本站声明:网站内容来源于网络,若有侵权,请联系我们,我们将及时处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值