jvm指令集: https://www.jianshu.com/p/d64a5dcccaa5
package com.kyle.springbase;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringbaseApplicationTests {
public static void main(String[] args) {
SpringbaseApplicationTests demo = new SpringbaseApplicationTests();
System.out.println(demo.add());
}
private int add() {
int a = 6;
int b = 10;
return a + b;
}
}
基于上述代码对jvm中某个class文件的字节码的执行顺序进行剖析。
IDEA中安装jclasslib插件,可以查看class文件的字节码指令执行顺序:
主要的方法调用如上图所述
<init>:构造方法的调用
main:调用了main方法
add:调用add方法
<clinit>:调用static静态代码快
<init>
aload | 将指定的引用类型本地变量推送至栈顶 |
invokespecial | 调用需要特殊处理的实例方法 |
1、引用本地方法区的地址,并放置到操作数栈的栈顶;
2、调用object对象的构造方法,生成空的demo对象;
3、return到上一次线程执行的地方,恢复现场,继续往下执行;
main
0 new #2 <com/kyle/springbase/SpringbaseApplicationTests>
3 dup
4 invokespecial #3 <com/kyle/springbase/SpringbaseApplicationTests.<init>>
7 astore_1
8 getstatic #4 <java/lang/System.out>
11 aload_1
12 invokespecial #5 <com/kyle/springbase/SpringbaseApplicationTests.add>
15 invokevirtual #6 <java/io/PrintStream.println>
18 return
astore | 将栈顶引用类型存入指定本地变量 |
getstatic | 获取指定类的静态域,并将其值压入栈顶 |
invokevirtual | 调用对象的实例方法 |
1、new了一个对象;
2、将该对象压入操作数栈栈顶;
3、调用构造方法;
4、调用astore方法,将对象pop出操作数栈,并存入局部变量表中index为1的位置(demo对象);
5、获取类的静态方法引用地址,并压入栈顶;
6、执行add方法;
7、调用System.out的实例方法;
8、return操作;
add
0 bipush 6
2 istore_1
3 bipush 10
5 istore_2
6 iload_1
7 iload_2
8 iadd
9 ireturn
bipush | 将单字节的数值(-128-127)压入栈顶 |
iconst_x | 将int类型的x推送到栈顶,x范围[0,5] |
istore_x | 将int类型的数值x存入局部变量表 |
iload_x | 将int类型的局部变量表中数值x推到栈顶 |
iadd | 将两个int类型的数值相加并推到栈顶 |
ireturn | 方法返回 |
1、将数值6压入栈顶;
2、将数值6存入局部变量表;
3、将数值10压入栈顶,再存入局部变量表;
4、将6和10压入栈顶,并相加后得到的数值压入栈顶;
5、返回int类型的数值
①将操作数栈的指针恢复成操作main方法的操作数栈指针;
②将局部变量表的指针恢复成main方法的局部变量表指针;
③程序计数器的地址变成main方法的地址;
④回收add占用的内存。