JVM-类的生命周期
1. 内容大纲
2. JVM-类的生命周期
在 JVM 中类的生命周期主要分为 加载、连接、初始化、使用和卸载 这五个部分,这五个部分具体内容如下:
- 加载阶段:主要将类字节码文件加载进 JVM 中。
- 连接阶段:这个部分主要包括验证、准备和解析。
- 初始化阶段:JVM 执行类的初始化代码,这些代码通常包括 静态变量赋值 和 静态代码块。
- 使用:类加载完成并经过初始化后,就可以被应用程序使用。
- 卸载:当类加载器不再需要某个类时,会触发类卸载过程。
3. JVM-类的加载阶段
在类加载阶段主要做的工作是将类的字节码数据加载到 JVM 中,具体内容如下:
查找对应加载类的字节码文件:类加载器负责根据类的全限定名去文件系统、网络等地方查找对应的字节码文件
类加载器加载完成之后,会分配内存空间给字节码文件
字节码文件的信息会保存到方法区中:类加载器加载类后,会将类的元数据信息存储到方法区中,包括类的结构信息、字段信息、方法信息等。
JVM 在堆中会创建一个与方法区中的类元数据相对应的
java.lang.Class
对象:这个类会包含运行时状态、方法的字节码等。这个对象是 Java 反射机制的基础.
4. JVM-类的连接阶段
JVM 连接阶段主要分为了三个部分,分别是 验证、准备、解析,具体内容如下:
- 验证:这个阶段主要判断字节码文件是否满足 JVM 规范,例如文件格式验证、元数据验证等等
- 准备:这个阶段主要是给类的静态变量分配内存空间并设置初始值,例如数值类型的默认值为 0 ,引用类型的默认值为 null。
- 解析:这个阶段主要是将符号引用转化为直接引用的过程,例如将类、方法和字段的符号引用转化为内存地址或偏移量。
4.1. 验证
验证阶段是确保加载的字节码文件符合 JVM 规范的过程:
文件格式校验,是否是以 0XCAFEBABE 开头
元信息验证,例如所有的类必须有父类
程序指令校验,例如方法内的指令执行到一般强制跳到其他方法中
符号引用验证,例如是否访问了其他类的 private 方法
符号引用和直接引用:https://blog.csdn.net/weixin_42447959/article/details/81675512
4.2. 准备
准备阶段是为类的静态变量分配内存空间并设置初始值的过程,例如每一种数据类型都有对应的默认值。
4.3. 解析
解析阶段是将类的符号引用转化为直接引用的过程。
5. JVM-类的初始化阶段
初始化阶段是执行类的初始化代码(静态变量赋值和静态代码块)的过程。
- 初始化阶段会执行 静态代码块中的代码,并为静态变量赋值,执行顺序与代码顺序一致。
如下是代码中通过 jclasslib
编译的一段代码,具体信息如下:
- [0]
: 构造方法 - [1] main:
Main
方法 - [2]
:初始化阶段执行
字节码位置 | 指令 | 注释 |
---|---|---|
0 | iconst_1 | 将 int 型常量值 1 推送至栈顶 |
1 | putstatic #2 | 将栈顶 int 型数值存入指定类的静态域 |
4 | iconst_2 | 将 int 型常量值 2 推送至栈顶 |
5 | putstatic #2 | 将栈顶 int 型数值存入指定类的静态域 |
8 | return | 从当前方法返回 void |
5.1. 类的初始化
如下几种方式会导致类的初始化:
- 访问一个类的静态变量或者静态方法。
- 调用 Class.forName(String className)。
- new 一个该类的对象。
- 执行 main() 的当前类
如下面试题信息,包含了上诉的这种情况
1 | public class Demo02 { |
- 打印的结果信息如下
1 | DACBCB |
5.2. 注意事项
在某些特定情况下并不会导致初始化指令的执行,具体内容如下:
- 无静态代码块且无静态变量赋值语句。
- 有静态变量的声明,但是没有赋值语句。
- 静态变量的定义使用 final 关键字,这类变量会在准备阶段直接进行初始化。
如下面试题信息,包含了上诉的这种情况
1 | public class Demo03 { |
我们修改如下内容
1 | public class Demo03 { |
6. 练习题
提示内容如下:
- 静态变量的定义使用 final 关键字,这类变量会在准备阶段直接进行初始化。
- 访问一个类的静态变量或者静态方法会导致类的初始化。
1 | public class Demo04 { |