从JVM分析Java的类的加载和卸载机制
类的加载
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.class对象,用来封装类在方法区内的数据结构。
加载.class文件的方式:
1.从本地系统中直接加载
2.通过网络下载.class文件
3.从zip,jar等归档文件中加载.class文件
4.从专有数据库中提取.class文件
5.将java源文件动态编译为.class文件
类的加载的最终产品是位于堆区中的class对象。
class对象封装了类在方法区内的数据结构,并且向java程序员提供了访问方法区内的数据结构的接口。
类加载器
加载器有两种类型:
1.java虚拟器自带的加载器
根类加载器(bootstrap)
扩展类加载器(extension)
系统类加载器或称应用加载器(system)
后两种加载器是java实现的,根类加载器是c++写的,程序员无法在java代码中获得该类。
2.用户自定义的类加载器
java.lang.classloader的子类
用户可以定制类的加载方式
类加载器并不需要等到某个类被首次主动使用时再加载它。
jvm规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(linkageerror)。如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误。
类的卸载机制
类的生命周期
当sample类被加载、连接和初始化后,它的生命周期就开始了。
当代表sample类的class对象不再被引用,即不可触及时,class对象就会结束生命周期,sample类在方法区内的数据也会被卸载,从而结束sample类的生命周期。
由此可见,一个类何时结束生命周期,取决于代表它的class对象何时结束生命周期。
引用关系
加载器和class对象:
在类加载器的内部实现中,用一个java集合来存放所加载类的引用。
另一方面,一个class对象总是会引用它的类加载器。调用class对象的getclassloader()方法,就能获得它的类加载器。
由此可见,class实例和加载它的加载器之间为双向关联关系。
类、类的class对象、类的实例对象:
一个类的实例总是引用代表这个类的class对象。
在object类中定义了getclass()方法,这个方法返回代表对象所属类的class对象的引用。
此外,所有的java类都有一个静态属性class,它引用代表这个类的class对象。
类的卸载
由java虚拟机自带的类加载器所加载的类,在虚拟机的生命周期中,始终不会被卸载。
前面介绍过,java虚拟机自带的类加载器包括根类加载器、扩展类加载器和系统类加载器。
java虚拟机本身会始终引用这些类加载器,而这些类加载器则会始终引用它们所加载的类的class对象,因此这些class对象始终是可触及的。
由用户自定义的类加载器加载的类是可以被卸载的。
具体例子
loader1变量和obj变量间接应用代表sample类的class对象,而objclass变量则直接引用它。
如果程序运行过程中,将上图左侧三个引用变量都置为null,此时sample对象结束生命周期,myclassloader对象结束生命周期,代表sample类的class对象也结束生命周期,sample类在方法区内的二进制数据被卸载。
当再次有需要时,会检查sample类的class对象是否存在,如果存在会直接使用,不再重新加载;如果不存在sample类会被重新加载,在java虚拟机的堆区会生成一个新的代表sample类的class实例(可以通过哈希码查看是否是同一个实例)。
推荐阅读
-
从JVM分析Java的类的加载和卸载机制
-
jvm之java类加载机制和类加载器(ClassLoader)的用法
-
java中获取类加载路径和项目根路径的5种方式分析
-
java中获取类加载路径和项目根路径的5种方式分析
-
[五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的
-
别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】
-
JVM类加载机制,java类的加载时机
-
[五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的
-
java中获取类加载路径和项目根路径的5种方式分析
-
别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】