文章目录⭐️写在前面
这里是温文艾尔の学习之路如果对你有帮助,给博主一个免费的点赞以示鼓励把QAQ博客主页 温文艾尔の学习小屋⭐️更多文章请关注温文艾尔主页文章发布日期:2021.12.29java学习之路!欢迎各位点赞评论收藏⭐️新年快乐朋友们jvm学习之路!⭐️上一篇内容:【JVM】JVM03(图解垃圾回收机制)下
1.字节码指令1.1入门1.2图解方法执行流程1.2.1常量池载入运行时常量池1.2.2方法字节码载入方法区1.2.3main线程开始运行,分配栈帧内存1.2.4执行引擎开始执行字节码
1.字节码指令 1.1入门
字节码指令可参考官方文档介绍
官方文档地址
原始java代码
public class Demo02 {
public static void main(String[] args) {
int a = 10;
int b = Short.MAX_VALUE + 1;
int c =a+b;
System.out.println(c);
}
}
通过javap工具反编译后的字节码文件
javap -v Demo02.class
Classfile /F:/2021年12月之后的Idea项目/jvmProject/out/production/jvmProj ect/com/wql/jvm/ClassInfo/Demo02.class Last modified 2022年1月22日; size 624 bytes SHA-256 checksum dc35d1e7095f253b0d5f0c8f3209953eba9fa5fc94f05edc6bc90 2db4f70f6ac Compiled from "Demo02.java" public class com.wql.jvm.ClassInfo.Demo02 minor version: 0 major version: 52 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #6 // com/wql/jvm/ClassInfo/Demo0 2 super_class: #7 // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 1 Constant pool: #1 = Methodref #7.#25 // java/lang/Object."":( )V #2 = Class #26 // java/lang/Short #3 = Integer 32768 #4 = Fieldref #27.#28 // java/lang/System.out:Ljava/ io/PrintStream; #5 = Methodref #29.#30 // java/io/PrintStream.println :(I)V #6 = Class #31 // com/wql/jvm/ClassInfo/Demo0 2 #7 = Class #32 // java/lang/Object #8 = Utf8 #9 = Utf8 ()V #10 = Utf8 Code #11 = Utf8 LineNumberTable #12 = Utf8 LocalVariableTable #13 = Utf8 this #14 = Utf8 Lcom/wql/jvm/ClassInfo/Demo02; #15 = Utf8 main #16 = Utf8 ([Ljava/lang/String;)V #17 = Utf8 args #18 = Utf8 [Ljava/lang/String; #19 = Utf8 a #20 = Utf8 I #21 = Utf8 b #22 = Utf8 c #23 = Utf8 SourceFile #24 = Utf8 Demo02.java #25 = NameAndType #8:#9 // " ":()V #26 = Utf8 java/lang/Short #27 = Class #33 // java/lang/System #28 = NameAndType #34:#35 // out:Ljava/io/PrintStream; #29 = Class #36 // java/io/PrintStream #30 = NameAndType #37:#38 // println:(I)V #31 = Utf8 com/wql/jvm/ClassInfo/Demo02 #32 = Utf8 java/lang/Object #33 = Utf8 java/lang/System #34 = Utf8 out #35 = Utf8 Ljava/io/PrintStream; #36 = Utf8 java/io/PrintStream #37 = Utf8 println #38 = Utf8 (I)V { public com.wql.jvm.ClassInfo.Demo02(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object ." ":()V 4: return LineNumberTable: line 9: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/wql/jvm/ClassInfo/Demo02; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=4, args_size=1 0: bipush 10 2: istore_1 3: ldc #3 // int 32768 5: istore_2 6: iload_1 7: iload_2 8: iadd 9: istore_3 10: getstatic #4 // Field java/lang/System. out:Ljava/io/PrintStream; 13: iload_3 14: invokevirtual #5 // Method java/io/PrintStr eam.println:(I)V 17: return LineNumberTable: line 11: 0 line 12: 3 line 13: 6 line 14: 10 line 15: 17 LocalVariableTable: Start Length Slot Name Signature 0 18 0 args [Ljava/lang/String; 3 15 1 a I 6 12 2 b I 10 8 3 c I } SourceFile: "Demo02.java"
执行流程
1.2.1常量池载入运行时常量池这里有一点误解,运行时常量池属于方法区,只是因为它相对比较特殊这里我们单独拎出来看,我们Class文件常量池中的数据,将来都要存储在运行时常量池
一些比较小的数字,比如int a=10;这些跟方法的字节码指令存在一起,而一旦数字的范围超过了整数最大值,他就会存储在常量池中,所以int b = Short.MAX_VALUE + 1;(32768)被存储在运行时常量池中
局部变量表是4,拥有4个槽位,栈的深度为2
绿色:局部变量表
蓝色:操作数栈1.2.4执行引擎开始执行字节码
bipush 10
将一个byte压入操作数栈(其长度会补齐4个字节),类似的指令还有sipush将一个short压入操作数栈(其长度会补齐4个字节)ldc将一个int压入操作数栈ldc2_w将一个long压入操作数栈(分两次压入,因为long是8个字节)这里小的数字都是和字节码指令存在一起,超过short范围的数字存入了常量池
istore_1
将操作数栈顶数据弹出,存入局部变量表的slot1
ldc #3
从常量池加载#3数据到操作数栈
注意Short.MAX_VALUE是32767,所以32768 = Short.MAX_VALUE + 1实际是在编译期间计算好的
istore_2
将栈顶数据弹出放入局部变量表的2号槽位
此处可以发现,32768(Short.MAX_VALUE + 1)是在编译期间就已经计算好了的,
iload_1
将局部变量表中1槽位的值读取到操作数栈
iload_2
将局部变量表中2槽位的值读取到操作数栈
iadd
依次弹出操作数栈栈顶的两个数字,进行相加操作,计算完毕后将结果压入操作数栈中
结果32778被压入栈
istore3
将操作数栈顶的元素放入局部变量表的3号槽位
getstatic #4
到常量池中找到#4,发现是成员变量的引用,它的实际对象存放在堆内存中,通过常量池找到堆中的system对象,将对象的引用放入操作数栈
iload_3
将局部变量表中3号槽位的c压入到操作数栈
invokevirtual #5
到运行时常量池找到#5定位到方法区java/io/PrintStream.println:(I)v方法生成新的栈帧(分配locals、stack等)传递参数,执行新栈帧中的字节码
等待栈帧执行完毕,将栈帧弹出并清除main操作数栈内容
return完成main方法调用,弹出main栈帧程序结束



