doc: 阅读jvm文档

This commit is contained in:
asahi
2025-12-18 13:04:11 +08:00
parent bd8afa5895
commit 4ccaead97a

View File

@@ -72,6 +72,11 @@
- [类加载时机](#类加载时机) - [类加载时机](#类加载时机)
- [加载](#加载) - [加载](#加载)
- [验证](#验证) - [验证](#验证)
- [准备](#准备)
- [解析](#解析)
- [符号引用](#符号引用)
- [直接引用](#直接引用)
- [初始化](#初始化-1)
# 深入理解java虚拟机 # 深入理解java虚拟机
@@ -634,4 +639,51 @@ class文件通过上述3个字段来确定类的继承关系。
### 验证 ### 验证
验证是连接阶段的第一步这一阶段目的是为了确保class文件中字节流包含信息符合当前虚拟机的要求。 验证是连接阶段的第一步这一阶段目的是为了确保class文件中字节流包含信息符合当前虚拟机的要求。
验证大致会完成下面四个阶段的检验动作:
- 文件格式验证:验证阶段的主要目的是保证输入的字节流能被正确解析并存储在方法区之内
- 是否以魔数`0XCAFEBABE`开头
- 主、次版本号是否在当前虚拟机的处理范围之内
- 常量池中常量是否有不被支持的常量类型
- class中各个部分及文件本身是否有被删除或附加的其他信息
- 元数据验证: 对字节码描述的信息进行语义分析确保其描述的信息符合java的语言规范要求
- 验证该类是否存在父类
- 验证该类是否继承了不允许被继承的类final类
- 如果这个类不是抽象类,校验其是否实现了父类或接口中所有要求实现的方法
- 类中的字段、方法是否和父类产生矛盾
- 字节码验证:通过数据流和控制分析,确保程序的语义是合法的、符合逻辑的
- 符号引用验证:确保解析动作能正常执行
### 准备
准备阶段会正式的为类变量static分配内存并设置类变量的初始值这些变量所使用的内存都会在方法区中进行分配。`在准备阶段并不会为实例变量分配内存空间实例变量将会在对象实例化时随着对象一起分配在java堆中。`
例如,存在一个类变量
```java
public static int value = 123;
```
那么value变量在准备阶段过后`值为0`而将value赋值为123的putstatic指令是在编译后存放于类构造器`<clinit>()`方法中的。
故而将value赋值为123的动作在初始化阶段才会执行。
> `<clinit>`方法是类构造器方法,而`<init>`方法是对象构造器方法,二者并不相同
但是,如果类变量按照如下方式声明
```java
public static final int value = 123
```
那么准备阶段value就会被直接赋值为123
### 解析
解析阶段是虚拟机将常量池内符号引用替换为直接引用的过程。
#### 符号引用
符号引用采用一组符号来描述所引用的目标,符号可以是任何形式的字面量。符号引用和虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。
各种虚拟机实现的内存布局可以不相同,但是它们能接受的符号引用必须都是一致的。
#### 直接引用
直接引用是可以直接指向目标的指针、相对偏移量或一个能间接定位到目标的句柄。
### 初始化
类初始化是类加载过程中的最后一步。在准备阶段,变量已经赋值过一次初始值,而在初始化阶段,`则会执行类构造器<clinit>()方法`