jovisoft 2019-06-21
这段时间一直在看JVM相关的书籍,虽然有点难,至少到目前为止还没有放弃。写这篇文章的目的:当做自己这段时间学习的小回顾。本章主要通过几个代码片段,分析下局部变量表与操作数栈之间的数据传递关系,重点讲解iload,istore,iconst_<n>,iadd命令
局部变量表:每个栈帧内部都包含一组称为局部变量表的变量列表
操作数栈:每个栈帧内部都包含一个操作数栈
iconst_0:把int型的0值压入操作数栈
iload:将一个局部变量加载到操作数栈上
istore:将一个数值从操作数栈上存储到局部变量表中
iadd:返回栈顶的两个元素做加法运算,并加结果压栈
首先通过dos进入TestApp.class所在的目录,然后运行命令javap -c TestApp,即可看到编译后的字节码文件
以下是一个java源代码
public void test1(){
int c=0;
}编译后的字节码
public void test1();
Code:
0: iconst_0
1: istore_1
2: return代码分析
因为test1()是一个实例方法,所以在局部变量表中,索引为0的位置会保存该方法所在类的引用(this),所以才会出现istore_1而不是istore_0。
我们对int c = 0做下拆解,一个常量0,一个变量c。
0: iconst_0 //将常量0压入操作数栈 1: istore_1 //将栈顶出栈,即c=0 2: return //因为是void,没有返回值
Java源代码如下
public static void test2(){
int c=0;
}编译后的字节码文件
public static void test2();
Code:
0: iconst_0
1: istore_0
2: return分析
因为test2()是一个静态的方法,不会在局部变量表中插入任何数据。所以你看到的是istore_0而不是像程序片段一中的istore_1。其他分析跟程序片段一相同
java源代码
public int test3(){
int c=0;
return c;
}编译后的字节码
public int test3();
Code:
0: iconst_0
1: istore_1
2: iload_1
3: ireturn分析
0: iconst_0 //将常量0压栈 1: istore_1 //将栈顶出栈,及c=0 2: iload_1 //将变量c压入栈顶 3: ireturn //返回栈定元素
Java源代码
public int test4(int a,int b){
int c=0;
return a+b;
}编译后的字节码
public int test4(int, int);
Code:
0: iconst_0
1: istore_3
2: iload_1
3: iload_2
4: iadd
5: ireturn** 分析
因为test4(int a,int b)是实例方法,所以在局部变量表索引为0的位置会插入this。
因为test4(int a,int b)带有两个参数,所以在局部变量索引索引为1的位置插入a,在索引为2的位置插入b。
0: iconst_0 //将常量0压栈 1: istore_3 //将栈顶出栈,即c=0,将c存储到局部变量表索引为3的位置 2: iload_1 //将局部变量表中索引为1的变量压栈,即a压栈 3: iload_2 //将局部变量表中索引为2的变量压栈,即b压栈 4: iadd //将栈顶两个元素出栈,做加法,然后把结果再入栈(即a,b出栈,将a+b入栈) 5: ireturn //返回a+b的值
java源代码
public int test5(int a,int b){
int c=0;
c= a+b;
return c;
}编译后的字节码
public int test5(int, int);
Code:
0: iconst_0
1: istore_3
2: iload_1
3: iload_2
4: iadd
5: istore_3
6: iload_3
7: ireturn分析
0: iconst_0 //将常量0压栈 1: istore_3 //将栈顶出栈,及c=0 2: iload_1 //从局部变量表中加载索引为1的变量压栈,即a压栈 3: iload_2 //从局部变量表中加载索引为2的变量压栈,即b压栈 4: iadd //将栈顶两个元素出栈,做加法,然后将结果压栈,及a+b压栈 5: istore_3 //将栈顶元素出栈,并保存到局部变量表中,即c=a+b 6: iload_3 //从局部变量表中加载索引为3的变量压栈,即c压栈 7: ireturn //返回栈顶元素,即返回c