操作数栈
操作数栈用于字节码指令执行期间,就像通用寄存器在CPU里使用一样。大部分JVM的字节码各自操作出栈,入栈,复制,交换,或者执行操作,使其生产和消费各种数据。因此,在字节码里,指令把值在局部变量表和操作数栈之间频繁移动。比如,一个简单的变量初始化导致两个字节码在操作数栈里交互影响。
int i;
编译后得到下面字节码:
0: iconst_0 // 将 0 入栈到操作数栈的顶端。
1: istore_1 // 从操作数栈顶端弹出并保存到局部变量
JVM字节码之整型入栈指令(iconst、bipush、sipush、ldc)
java里的常见整形长度表示范围:
byte的取值范围为-128~127,占用1个字节(-2的7次方到2的7次方-1)
short的取值范围为-32768~32767,占用2个字节(-2的15次方到2的15次方-1)
int的取值范围为(-2147483648~2147483647),占用4个字节(-2的31次方到2的31次方-1)
long的取值范围为(-9223372036854774808~9223372036854774807),占用8个字节(-2的63次方到2的63次方-1)
当int取值-1~5:int取值0~5时JVM采用iconst_0、iconst_1、iconst_2、iconst_3、iconst_4、iconst_5指令将常量压入栈中,取值-1时采用iconst_m1指令将常量压入栈中
取值-128~127采用bipush指令(bipush 127),
取值-32768~32767采用sipush指令(sipush 32767)
取值-2147483648~2147483647采用 ldc 指令(ldc #2; //int 2147483647从常量池中获取值)。
java的栈
线程-线程的栈,栈帧-方法,线程执行方法时,就是栈帧出栈,入栈的过程。
栈帧:三部分:本地变量(参数+方法内的变量)、操作数栈和其他数据
①int i = 0;
i = i++;
②int i = 0;
i = ++i;
③int i = 0;
int j = 0;
j = i++ + i++;
④ int i = 0;
int j = 0;
j = i++ + i++ + i++;
Bytecode |
Stack before->after |
Description |
iconst_0 |
->0 |
Loads the int value 0 onto the stack |
istore_1 |
value-> |
Store int value into variable 1 |
istore_2 |
value-> |
Store int value into variable 2 |
iinc |
No change |
Increment local variable #index by signed byte const |
iload_1 |
->value |
Loads an int value from variable 1 |
iadd |
value 1,value 2->result |
Adds 2 ints together |
说明两点需要注意的地方:
①iinc操作是有参数的,但是在此忽略,简写为iinc,此操作对应于自加操作,并且该操作不对stack有任何改变;
②iadd操作过后只在stack中保留结果result。
接下来是四段程序主要的字节码:
①iconst_0 ②iconst_0 ③iconst_0 ④iconst_0
istore_1 istore_1 istore_1 istore_1
iload_1 iinc 1,1 iconst_0 iconst_0
iinc 1,1 iload_1 istore_2 istore_2
istore_1 istore_1 iload_1 iload_1
iinc 1,1 iinc 1,1
iload_1 iload_1
iinc 1,1 iinc 1,1
iadd iadd
istore_2 iload_1
iinc 1,1
iadd
istore_2