事先创建一个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返回