本篇主要介绍一下JVM类加载的过程。类从被JVM加载到内存到从内存中卸载,其生命周期包括:加载(loading)、验证(verifying)、准备(preparing)、解析(resolving)、初始化(initialisaing)、使用(using)和卸载(unloading)7个阶段。其中加载、验证、准备、初始化、和卸载的顺序是固定的,解析有可能会在初始化之后进行。如下图所示:
1、加载:在类加载阶段主要完成以下三件事情:①通过此类的全限定名来获取此类的二进制字节流。②将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。③在java堆中生成对应的java.lang.Class对象。java字节码的获取方式可以有以下几种方式:
- (1)从ZIP包中获取(如jar、ear、war等)
- (2)从网络中获取
- (3)运行时动态生成,使用最多的就是动态代理(如:JDK动态代理、CGLIB动态代理)
- (4)其他文件生成(如JSP编译生成对应的class文件)
- (5)从数据库中读取(相对较少)
2、验证:验证的目的是保证字节码文件是正确的。验证的方式主要有以下几种:①文件格式的验证;②元数据验证;③字节码验证(很复杂);④符号引用验证
(1)文件格式的验证
- ①是否以0XCAFEBABY开头
- ②主次版本号是否在当前JVM处理范围之内
- ③常量池中是否有不被支持的常量
- ......
(2)元数据验证
- ①是否有父类
- ②继承了final类?
- ③非抽象类实现了所有的抽象方法
- ......
(3)字节码验证
- ①运行检查
- ②栈数据类型和操作码数据参数吻合
- ③跳转指令指定到合理的位置
- ......
(4)符号引用验证
- ①符号引用中通过字符串描述的权限定名是否能找到对应的类
- ②类中是否存在符合方法的字段描述以及简单名称所描述的方法和字段
- ③符号引用中的类、字段、方法的访问性是否可以被当前类访问
- ......
3、准备:准备阶段就是为static类型的变量分配初始值(如int类型的初始值为0),需要注意的是当变量类型为static final时,准备阶段就将其赋值为最终的值。
4、解析:JVM将常量池内的符号引用(与JVM无关)转化为直接引用(与JVM相关)。解析动作主要针对于类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用。
5、初始化:初始化阶段包括执行构造器<clinit>,其中包括了static变量赋值语句和static{}静态块;子类的<clinit>调用之前保证父类的<clinit>被调用;还有一点就是<clinit>是线程安全的。
时间: 2024-10-11 04:26:52