字节码指令以及操作数栈的分析
事先创建一个java类,如下:
package com.yang.jvm; public class Demo { public int getNum(){ int a=1; int b=2; int c=3; int d=4; return (a+b-c)*d; } }
在命令窗口输入:F:\jvmdemo>javap -c -verbose build/classes/java/main/com/yang/jvm/Demo.class
执行命令后获得字节码文件内容:
Classfile /F:/jvmdemo/build/classes/java/main/com/yang/jvm/Demo.class
Last modified 2019-10-23; size 428 bytes
MD5 checksum b4f01d8c01f685e501ee4f8dc209652d
Compiled from "Demo.java"
public class com.yang.jvm.Demo
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#20 // java/lang/Object."<init>":()V
#2 = Class #21 // com/yang/jvm/Demo
#3 = Class #22 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 Lcom/yang/jvm/Demo;
#11 = Utf8 getNum
#12 = Utf8 ()I
#13 = Utf8 a
#14 = Utf8 I
#15 = Utf8 b
#16 = Utf8 c
#17 = Utf8 d
#18 = Utf8 SourceFile
#19 = Utf8 Demo.java
#20 = NameAndType #4:#5 // "<init>":()V
#21 = Utf8 com/yang/jvm/Demo
#22 = Utf8 java/lang/Object
{
public com.yang.jvm.Demo();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/yang/jvm/Demo;
public int getNum();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=2, locals=5, args_size=1
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: iconst_3
5: istore_3
6: iconst_4
7: istore 4
9: iload_1
10: iload_2
11: iadd
12: iload_3
13: isub
14: iload 4
16: imul
17: ireturn
LineNumberTable:
line 6: 0
line 7: 2
line 8: 4
line 9: 6
line 10: 9
LocalVariableTable:
Start Length Slot Name Signature
0 18 0 this Lcom/yang/jvm/Demo;
2 16 1 a I
4 14 2 b I
6 12 3 c I
9 9 4 d I
}
SourceFile: "Demo.java"
F:\jvmdemo>javap -c -verbose build/classes/java/main/com/yang/jvm/Demo.class
Classfile /F:/jvmdemo/build/classes/java/main/com/yang/jvm/Demo.class
Last modified 2019-10-23; size 428 bytes
MD5 checksum b4f01d8c01f685e501ee4f8dc209652d
Compiled from "Demo.java"
public class com.yang.jvm.Demo
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#20 // java/lang/Object."<init>":()V
#2 = Class #21 // com/yang/jvm/Demo
#3 = Class #22 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 Lcom/yang/jvm/Demo;
#11 = Utf8 getNum
#12 = Utf8 ()I
#13 = Utf8 a
#14 = Utf8 I
#15 = Utf8 b
#16 = Utf8 c
#17 = Utf8 d
#18 = Utf8 SourceFile
#19 = Utf8 Demo.java
#20 = NameAndType #4:#5 // "<init>":()V
#21 = Utf8 com/yang/jvm/Demo
#22 = Utf8 java/lang/Object
{
public com.yang.jvm.Demo();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/yang/jvm/Demo;
public int getNum();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=2, locals=5, args_size=1
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: iconst_3
5: istore_3
6: iconst_4
7: istore 4
9: iload_1
10: iload_2
11: iadd
12: iload_3
13: isub
14: iload 4
16: imul
17: ireturn
LineNumberTable:
line 6: 0
line 7: 2
line 8: 4
line 9: 6
line 10: 9
LocalVariableTable:
Start Length Slot Name Signature
0 18 0 this Lcom/yang/jvm/Demo;
2 16 1 a I
4 14 2 b I
6 12 3 c I
9 9 4 d I
}
SourceFile: "Demo.java"
本次需要分析的字节码内容如下:

java虚拟机栈和栈帧关系图:

栈帧的组成:局部变量表,操作数栈,动态链接,方法出口
由字节码文件可以看到,栈深度为2(stack=2)说明操作数栈的深度是2,本地变量表变量长度为5因此过程分析如下:
0.指令 iconst_1 意义:将常量1压入操作数栈的栈顶

1.指令istore_1:意义将操作数栈顶的数字弹出,然后赋值给局部变量表索引为1的变量,索引为0的变量为this
![]()
将常量1入栈,并存到栈顶


2. 同理 iconst_2 和 istore_2 分别表示将常量2入栈,存到栈顶,然后出栈,赋值给局部变量表索引为2的变量
3.之后的指令 iconst_3 和 istore_3 , iconst_4 和 istore 4 同理,他们执行完后此时操作数栈和局部变量表如下:

4. 之后执行 iload_1,意义是将局部变量表索引为1的变量压入操作数栈的栈顶

5.同理:iload_2,意义是将局部变量表索引为2的变量压入操作数栈的栈顶此时:

6.指令iadd,表示将操作数栈的2个值弹出,然后计算他们的和,之后将结果压入栈顶

此时:

7.之后执行命令iload_3,表示将局部变量索引为3的变量入栈,到栈顶,此时:
8.isub将操作数栈的2个数弹出,然后做减法,之后将结果压入栈顶

9. iload 4 表示将局部变量索引为4的变量压入栈顶:此时

10. imul 表示将操作数栈的2个数弹出,并做乘法运算,之后将结果压入栈顶:
11.ireturn指令:将操作数栈顶的数弹出,然后压入调用者的操作数栈的栈顶,如果操作操作数栈除了栈顶的内容外还有其他内容,其他内容都会被丢弃掉,所以这里将0返回




浙公网安备 33010602011771号