概述
- 类文件结构
- 字节码指令
- 编译期处理
- 类加载阶段
- 类加载器
- 运行期优化
类文件结构
一个简单的HelloWorld.java
package cn.chasing.jvm.t3
// HelloWorld示例
public class HelloWorld {
public static void main(String[] args) {
System.out.println("hello world");
}
}
执行
javac -parameters -d . HelloWorld.java
编译为HelloWorld.class后是这个样子,以八进制表示
根据JVM规范,类文件结构如下
魔数
0~3字节,表示它是否是【class】类型文件
版本
4~7字节,表示类的版本00 32 (52) 表示是java8
常量池
Constant Type | Value |
---|---|
CONSTANT_Class | 7 |
CONSTANT_Fieldref | 9 |
CONSTANT_Methodref | 10 |
CONSTANT_InterfaceMethodref | 11 |
CONSTANT_String | 8 |
CONSTANT_Integer | 3 |
CONSTANT_Float | 4 |
CONSTANT_Long | 5 |
CONSTANT_Double | 6 |
CONSTANT_NameAndType | 12 |
CONSTANT_Utf8 | 1 |
CONSTANT_MethodHandle | 15 |
CONSTANT_MethodType | 16 |
CONSTANT_InvokeDynamic | 18 |
8~9 字节,表示常量池长度,00 23 (35) 表示常量池有 #1~#34项,注意 #0 项不计入,也没有值
第#1项 0a 表示一个 Method 信息,00 06 和 00 15(21) 表示它引用了常量池中 #6 和 #21 项来获得这个方法的【所属类】和【方法名】
第#2项 09 表示一个 Field 信息,00 16(22)和 00 17(23) 表示它引用了常量池中 #22 和 # 23 项来获得这个成员变量的【所属类】和【成员变量名】
第#3项 08 表示一个字符串常量名称,00 18(24)表示它引用了常量池中 #24 项
第#4项 0a 表示一个 Method 信息,00 19(25) 和 00 1a(26) 表示它引用了常量池中 #25 和 #26项来获得这个方法的【所属类】和【方法名】
第#5项 07 表示一个 Class 信息,00 1b(27) 表示它引用了常量池中 #27 项
第#6项 07 表示一个 Class 信息,00 1c(28) 表示它引用了常量池中 #28 项
第#7项 01 表示一个 utf8 串,00 06 表示长度,3c 69 6e 69 74 3e 是【 】,构造方法
第#8项 01 表示一个 utf8 串,00 03 表示长度,28 29 56 是【()V】其实就是表示无参、无返回值
第#9项 01 表示一个 utf8 串,00 04 表示长度,43 6f 64 65 是【Code】
第#10项 01 表示一个 utf8 串,00 0f(15) 表示长度,4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65是【LineNumberTable】
第#11项 01 表示一个 utf8 串,00 12(18) 表示长度,4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65是【LocalVariableTable】
第#12项 01 表示一个 utf8 串,00 04 表示长度,74 68 69 73 是【this】
第#13项 01 表示一个 utf8 串,00 1d(29) 表示长度,是【Lcn/itcast/jvm/t5/HelloWorld;】
第#14项 01 表示一个 utf8 串,00 04 表示长度,74 68 69 73 是【main】
第#15项 01 表示一个 utf8 串,00 16(22) 表示长度,是【([Ljava/lang/String;)V】其实就是参数为字符串数组,无返回值
第#16项 01 表示一个 utf8 串,00 04 表示长度,是【args】
第#17项 01 表示一个 utf8 串,00 13(19) 表示长度,是【[Ljava/lang/String;】
第#18项 01 表示一个 utf8 串,00 10(16) 表示长度,是【MethodParameters】
第#19项 01 表示一个 utf8 串,00 0a(10) 表示长度,是【SourceFile】
第#20项 01 表示一个 utf8 串,00 0f(15) 表示长度,是【HelloWorld.java】
第#21项 0c 表示一个 【名+类型】,00 07 00 08 引用了常量池中 #7 #8 两项
第#22项 07 表示一个 Class 信息,00 1d(29) 引用了常量池中 #29 项
第#23项 0c 表示一个 【名+类型】,00 1e(30) 00 1f (31)引用了常量池中 #30 #31 两项
第#24项 01 表示一个 utf8 串,00 0f(15) 表示长度,是【hello world】
第#25项 07 表示一个 Class 信息,00 20(32) 引用了常量池中 #32 项
第#26项 0c 表示一个 【名+类型】,00 21(33) 00 22(34)引用了常量池中 #33 #34 两项
第#27项 01 表示一个 utf8 串,00 1b(27) 表示长度,是【cn/itcast/jvm/t5/HelloWorld】
第#28项 01 表示一个 utf8 串,00 10(16) 表示长度,是【java/lang/Object】
第#29项 01 表示一个 utf8 串,00 10(16) 表示长度,是【java/lang/System】
第#30项 01 表示一个 utf8 串,00 03 表示长度,是【out】
第#31项 01 表示一个 utf8 串,00 15(21) 表示长度,是【Ljava/io/PrintStream;】
第#32项 01 表示一个 utf8 串,00 13(19) 表示长度,是【java/io/PrintStream】
第#33项 01 表示一个 utf8 串,00 07 表示长度,是【println】
第#34项 01 表示一个 utf8 串,00 15(21) 表示长度,是【(Ljava/lang/String;)V】
访问标识与继承信息
Field 信息
Method 信息
一个方法由 访问修饰符,名称,参数描述,方法属性数量,方法属性组成
-
红色代表访问修饰符(本类中是 public)
-
蓝色代表引用了常量池 #07 项作为方法名称
-
绿色代表引用了常量池 #08 项作为方法参数描述
-
黄色代表方法属性数量,本方法是 1
-
红色代表方法属性
-
00 09 表示引用了常量池 #09 项,发现是【Code】属性
-
00 00 00 2f 表示此属性的长度是 47
-
00 01 表示【操作数栈】最大深度
-
00 01 表示【局部变量表】最大槽(slot)数
-
2a b7 00 01 b1 是字节码指令
-
00 00 00 02 表示方法细节属性数量,本例是 2
-
00 0a 表示引用了常量池 #10 项,发现是【LineNumberTable】属性
- 00 00 00 06 表示此属性的总长度,本例是 6
- 00 01 表示【LineNumberTable】长度
- 00 00 表示【字节码】行号 00 04 表示【java 源码】行号
-
00 0b 表示引用了常量池 #11 项,发现是【LocalVariableTable】属性
- 00 00 00 0c 表示此属性的总长度,本例是 12
- 00 01 表示【LocalVariableTable】长度
- 00 00 表示局部变量生命周期开始,相对于字节码的偏移量
- 00 05 表示局部变量覆盖的范围长度
- 00 0c 表示局部变量名称,本例引用了常量池 #12 项,是【this】
- 00 0d 表示局部变量的类型,本例引用了常量池 #13 项,是【Lcn/itcast/jvm/t5/HelloWorld;】
- 00 00 表示局部变量占有的槽位(slot)编号,本例是 0
-
-
红色代表访问修饰符(本类中是 public static)
-
蓝色代表引用了常量池 #14 项作为方法名称
-
绿色代表引用了常量池 #15 项作为方法参数描述
-
黄色代表方法属性数量,本方法是 2
-
红色代表方法属性(属性1)
- 00 09 表示引用了常量池 #09 项,发现是【Code】属性
- 00 00 00 37 表示此属性的长度是 55
- 00 02 表示【操作数栈】最大深度
- 00 01 表示【局部变量表】最大槽(slot)数
- 00 00 00 09 表示字节码长度,本例是 9
- b2 00 02 12 03 b6 00 04 b1 是字节码指令
- 00 00 00 02 表示方法细节属性数量,本例是 2
- 00 0a 表示引用了常量池 #10 项,发现是【LineNumberTable】属性
- 00 00 00 0a 表示此属性的总长度,本例是 10
- 00 02 表示【LineNumberTable】长度
- 00 00 表示【字节码】行号 00 06 表示【java 源码】行号
- 00 08 表示【字节码】行号 00 07 表示【java 源码】行号
- 00 0b 表示引用了常量池 #11 项,发现是【LocalVariableTable】属性
- 00 00 00 0c 表示此属性的总长度,本例是 12
- 00 01 表示【LocalVariableTable】长度
- 00 10 表示局部变量名称,本例引用了常量池 #16 项,是【args】
- 00 11 表示局部变量的类型,本例引用了常量池 #17 项,是【[Ljava/lang/String;】
- 00 00 表示局部变量占有的槽位(slot)编号,本例是 0
红色代表方法属性(属性2)
- 00 12 表示引用了常量池 #18 项,发现是【MethodParameters】属性
- 00 00 00 05 表示此属性的总长度,本例是 5
- 01 参数数量
- 00 10 表示引用了常量池 #16 项,是【args】
- 00 00 访问修饰符
附加属性
- 00 01 表示附加属性数量
- 00 13 表示引用了常量池 #19 项,即【SourceFile】
- 00 00 00 02 表示此属性的长度
- 00 14 表示引用了常量池 #20 项,即【HelloWorld.java】
参考文献
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html