JVM学习(五):类加载机制
1、类加载机制的含义:Java程序运行期间,虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。
2、类在虚拟机中的生命周期:
(1)分为7个阶段:加载、验证、准备、解析、初始化、使用和卸载。
(2)验证、准备、解析统称为连接。
(3)加载、验证、准备、初始化和卸载这5个阶段的开始顺序是确定的。解析阶段则不一定,在某些情况下可以在初始化阶段之后开始,为的是支持Java语言的运行时绑定。
3、类加载的过程:
(1)类加载的过程包括加载、验证、准备、解析和初始化5个阶段。
(2)加载是类加载过程的一个阶段,一个非数组类的加载阶段是开发人员可控性最强的,用户可以自定义类加载器(即重写一个类加载器的loadClass()方法)。数组类本身不通过类加载器创建,它是由Java虚拟机直接创建的。
(3)验证是连接阶段的第一步,包括文件格式验证、元数据验证、字节码验证和符号引用验证等。验证不是一定必要的阶段,如果所运行的全部代码已经被反复使用和验证过,在实施阶段可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。
(4)准备是正式为类变量(被static修饰的变量)分配内存并设置初始值(通常为零值)的阶段。
(5)解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,包括类或接口的解析、字段解析(可抛出java.lang.NoSuchFieldError)、类方法解析(可抛出java.lang.NoSuchMethodError)、接口方法解析(可抛出java.lang.NoSuchMethodError)。
(6)初始化阶段是类加载过程的最后一步,到了初始化阶段,才真正开始执行类中定义的Java程序代码(或说是字节码),初始化阶段是执行类构造器<clinit>()方法的过程,在虚拟机中第一个被执行的<clinit>()方法的类肯定是java.lang.Object。
4、类加载器
(1)定义:通过一个类的全限定名来获取描述此类的二进制字节流,在虚拟机外部实现这个动作的代码模块。
(2)两个类是否相等:包括Class对象的equals()、isAssignableFrom()、isInstance()以及instanceof关键字的判断,只有在这两个类是由同一个类加载器加载的前提下判断才有意义。
(3)类加载器的种类有:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)、应用程序类加载器(Application ClassLoader)和自定义类加载器(User ClassLoader)。
(4)双亲委派模型:除了启动类加载器外,其余类加载器都应该有自己的父类加载器,如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是委派给父类加载器加载,每一层都是如此,最终传送到顶层的启动类加载器中,只有父类加载器反馈无法完成加载请求,子类加载器才会尝试自己加载。
(5)由于双亲委派模型的限制,java.lang下面的类只能由启动加载器加载,即使重写rt.jar类库中的Java类,可以正常编译,但永远无法被加载运行。
(6)如果父类加载失败,会抛出ClassNotFoundException异常,然后调用自己的findClass()方法进行加载。
5、OSGi:实现模块化热部署的关键是它自定义的类加载器机制的实现,每一个程序模块(OSGi中称为Bundle)都有一个自己的类加载器,当需要更换一个Bundle时,就把Bundle连同类加载器一起换掉以实现代码的热替换。