类加载器的命名空间

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

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

  • 每个类加载器又有一个命名空间,由其以及其父加载器组成
  • 在每个类加载器自己的命名空间中不能出现相同类名的类 (此处值得是类的全名,包含包名)
  • 在不同的类命名空间中,可能会出现多个相同的类名的类

如下面的代码示例中, 首先定义一个类加载器 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

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

【深入理解Java虚拟机 】类加载器的命名空间以及类的卸载的更多相关文章

  1. 深入理解Java虚拟机 - 类加载器

    引子:       类加载器(classloader)是独立于虚拟机之外,可以独立实现的代码模块.     OSGi使用了类加载器的这一特点实现其热插拔的特性       Java同C++等语言不通, ...

  2. Java虚拟机类加载器及双亲委派机制

    所谓的类加载器(Class Loader)就是加载Java类到Java虚拟机中的,前面<面试官,不要再问我"Java虚拟机类加载机制"了>中已经介绍了具体加载class ...

  3. 深入理解Java虚拟机学习笔记(三)-----类文件结构/虚拟机类加载机制

    第6章 类文件结构 1. 无关性 各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节码(即扩展名为 .class 的文件) 是构成平台无关性的基石. 字节码(即扩展名为 .class 的文 ...

  4. 深入理解java虚拟机----->垃圾收集器与内存分配策略(下)

    1.  前言 内存分配与回收策略 JVM堆的结构分析(新生代.老年代.永久代) 对象优先在Eden分配 大对象直接进入老年代 长期存活的对象将进入老年代 动态对象年龄判定 空间分配担保  2.  垃圾 ...

  5. 深入理解Java虚拟机类加载机制

    1.类加载时机 对于类加载的第一个阶段---加载,虚拟机没有强制的约束,但是对于初始化阶段,虚拟机强制规定有且只有以下的5中情况必须开始初始化,当然,加载.验证.准备阶段在初始化前就已经开始. ①使用 ...

  6. 深入理解Java虚拟机---类加载机制(简略版)

    类加载机制 谈起类加载机制,在这里说个题外话,当初本人在学了两三个月的Java后,只了解了一些皮毛知识,就屁颠屁颠得去附近学校的招聘会去蹭蹭面试经验,和HR聊了一会后开始了技术面试,前抛出了两个简单的 ...

  7. Java 虚拟机类加载器

    虚拟机设计团队把类加载阶段张的”通过一个类的全限定名来获取此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码模块称为”类加载器”. ...

  8. 深入理解Java虚拟机-类加载连接和初始化解析

    不管学习什么,我一直追求的是知其然,还要知其所以然,对真理的追求可以体现在方方面面.人生短短数十载,匆匆一世似烟云,我认为,既然来了,就应该留下一些有意义的东西.本系列文章是结合张龙老师的<深入 ...

  9. 深入理解JAVA虚拟机 垃圾收集器和内存分配策略

    引用计数算法 很多教科书判断对象是否存活的算法是这样的:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器都为0的对象就是不可能再被使用的 ...

随机推荐

  1. collection-time-os-sys-json模块

    一.collections模块 美 [kə'lekʃənz] ,收集,收藏 在内置数据(dict  list  set  tuple)的基础上,collections模块海提供了几个常用的数据类型:c ...

  2. video文件转blob

    //创建 XMLHttpRequest 对象 var xhr = new XMLHttpRequest(); //配置请求方式.请求地址以及是否同步 xhr.open('POST', './play' ...

  3. Python基础——类new方法与单例模式

    介绍: new方法是类中魔术方法之一,他的作用是给类实例化开辟一个内存地址,并返回一个实例化,再由__init__对这个实例进行初始化,故它的执行肯定就是在初始化方法__init__之前了.new方法 ...

  4. QT程序中显示中文字体解决办法

    Qt4.7.1 默认没有中文字体库,迅为给用户提供“文泉驿”字体和配置方法.本节需要的 文件在网盘: 用一个简单测试程序说明“文泉驿”字体的配置方法. 在 Qt Creater 新建工程“nihao” ...

  5. 查看linux系统安装的服务

    如何查看linux系统安装了哪些服务呢,因不同版本的操作系统可能使用的命令不一样或者有些命令在某些操作系统不可用,现列举一些常用查看命令(基于我的linux版本). 我的操作系统版本如下: 1.ser ...

  6. Excel-DNA自定义函数的参数智能提示功能:ExcelDna.IntelliSense1.1.0.rar

    解压缩后,可以看到如下3个文件. ExcelDna.IntelliSense.xll 以及 ExcelDna.IntelliSense64.xll 是两个函数参数智能提示加载项,分别用于32和64位E ...

  7. JAVA专业术语面试100问

    前言:面试技巧另外开篇再说,先上面试干货吧.Redis.消息队列.SQL不要走开,关注后更精彩! 1.面向对象的特点有哪些? 抽象.继承.封装.多态. 2.接口和抽象类有什么联系和区别? 3.重载和重 ...

  8. IoC容器设计

    本文主要摘录于  Spring技术内幕-深入即系Spring架构和设计原理(许文柯著). IoC是根据两个核心BeanFactory和ApplicationContext来设计的,这里先放一张Spri ...

  9. SQL中的一些关键字用法

    1.where 条件筛选结果 select * from `表名` where `列名`='value' 上诉语句的意思是在某表中查询某列名等于某特定值得所有列 2.Like 模糊查询 select ...

  10. [洛谷P3806] [模板] 点分治1

    洛谷 P3806 传送门 这个点分治都不用减掉子树里的了,直接搞就行了. 注意第63行 if(qu[k]>=buf[j]) 不能不写,也不能写成>. 因为这个WA了半天...... 如果m ...