【JVM】JVM04(类加载与字节码-图解方法执行流程)

⭐️写在前面


  • 这里是温文艾尔の学习之路
  • 如果对你有帮助,给博主一个免费的点赞以示鼓励把QAQ
  • 博客主页 温文艾尔の学习小屋
  • ⭐️更多文章‍请关注温文艾尔主页
  • 文章发布日期:2021.12.29
  • java学习之路!
  • 欢迎各位点赞评论收藏⭐️
  • 新年快乐朋友们
  • jvm学习之路!
  • ⭐️上一篇内容:【JVM】JVM03(图解垃圾回收机制)下

文章目录

  • 1.字节码指令
  • 1.1入门
  • 1.2图解方法执行流程
  • 1.2.1常量池载入运行时常量池
  • 1.2.2方法字节码载入方法区
  • 1.2.3main线程开始运行,分配栈帧内存
  • 1.2.4执行引擎开始执行字节码


1.字节码指令

1.1入门

字节码指令可参考官方文档介绍
官方文档地址

【JVM】JVM04(类加载与字节码-图解方法执行流程)_第1张图片

1.2图解方法执行流程

原始java代码

public class Demo02 {
    public static void main(String[] args) {
        int a = 10;
        int b = Short.MAX_VALUE + 1;
        int c =a+b;
        System.out.println(c);
    }
}

通过javap工具反编译后的字节码文件

javap -v Demo02.class
Classfile /F:/202112月之后的Idea项目/jvmProject/out/production/jvmProj
ect/com/wql/jvm/ClassInfo/Demo02.class
  Last modified 2022122; size 624 bytes
  SHA-256 checksum dc35d1e7095f253b0d5f0c8f3209953eba9fa5fc94f05edc6bc90
2db4f70f6ac
  Compiled from "Demo02.java"
public class com.wql.jvm.ClassInfo.Demo02
  minor version: 0
  major version: 52
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #6                          // com/wql/jvm/ClassInfo/Demo0
2
  super_class: #7                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #7.#25         // java/lang/Object."":(
)V
   #2 = Class              #26            // java/lang/Short
   #3 = Integer            32768
   #4 = Fieldref           #27.#28        // java/lang/System.out:Ljava/
io/PrintStream;
   #5 = Methodref          #29.#30        // java/io/PrintStream.println
:(I)V
   #6 = Class              #31            // com/wql/jvm/ClassInfo/Demo0
2
   #7 = Class              #32            // java/lang/Object
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               LocalVariableTable
  #13 = Utf8               this
  #14 = Utf8               Lcom/wql/jvm/ClassInfo/Demo02;
  #15 = Utf8               main
  #16 = Utf8               ([Ljava/lang/String;)V
  #17 = Utf8               args
  #18 = Utf8               [Ljava/lang/String;
  #19 = Utf8               a
  #20 = Utf8               I
  #21 = Utf8               b
  #22 = Utf8               c
  #23 = Utf8               SourceFile
  #24 = Utf8               Demo02.java
  #25 = NameAndType        #8:#9          // "":()V
  #26 = Utf8               java/lang/Short
  #27 = Class              #33            // java/lang/System
  #28 = NameAndType        #34:#35        // out:Ljava/io/PrintStream;
  #29 = Class              #36            // java/io/PrintStream
  #30 = NameAndType        #37:#38        // println:(I)V
  #31 = Utf8               com/wql/jvm/ClassInfo/Demo02
  #32 = Utf8               java/lang/Object
  #33 = Utf8               java/lang/System
  #34 = Utf8               out
  #35 = Utf8               Ljava/io/PrintStream;
  #36 = Utf8               java/io/PrintStream
  #37 = Utf8               println
  #38 = Utf8               (I)V
{
  public com.wql.jvm.ClassInfo.Demo02();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object
."":()V
         4: return
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/wql/jvm/ClassInfo/Demo02;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: bipush        10
         2: istore_1
         3: ldc           #3                  // int 32768
         5: istore_2
         6: iload_1
         7: iload_2
         8: iadd
         9: istore_3
        10: getstatic     #4                  // Field java/lang/System.
out:Ljava/io/PrintStream;
        13: iload_3
        14: invokevirtual #5                  // Method java/io/PrintStr
eam.println:(I)V
        17: return
      LineNumberTable:
        line 11: 0
        line 12: 3
        line 13: 6
        line 14: 10
        line 15: 17
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      18     0  args   [Ljava/lang/String;
            3      15     1     a   I
            6      12     2     b   I
           10       8     3     c   I
}
SourceFile: "Demo02.java"

执行流程

1.2.1常量池载入运行时常量池

这里有一点误解,运行时常量池属于方法区,只是因为它相对比较特殊这里我们单独拎出来看,我们Class文件常量池中的数据,将来都要存储在运行时常量池
【JVM】JVM04(类加载与字节码-图解方法执行流程)_第2张图片
一些比较小的数字,比如int a=10;这些跟方法的字节码指令存在一起,而一旦数字的范围超过了整数最大值,他就会存储在常量池中,所以int b = Short.MAX_VALUE + 1;(32768)被存储在运行时常量池中

1.2.2方法字节码载入方法区

【JVM】JVM04(类加载与字节码-图解方法执行流程)_第3张图片

1.2.3main线程开始运行,分配栈帧内存

局部变量表是4,拥有4个槽位,栈的深度为2

绿色:局部变量表
蓝色:操作数栈

【JVM】JVM04(类加载与字节码-图解方法执行流程)_第4张图片

1.2.4执行引擎开始执行字节码

bipush 10

  • 将一个byte压入操作数栈(其长度会补齐4个字节),类似的指令还有
  • sipush将一个short压入操作数栈(其长度会补齐4个字节)
  • ldc将一个int压入操作数栈
  • ldc2_w将一个long压入操作数栈(分两次压入,因为long是8个字节)
  • 这里小的数字都是和字节码指令存在一起,超过short范围的数字存入了常量池
    【JVM】JVM04(类加载与字节码-图解方法执行流程)_第5张图片

istore_1

将操作数栈顶数据弹出,存入局部变量表的slot1

【JVM】JVM04(类加载与字节码-图解方法执行流程)_第6张图片
【JVM】JVM04(类加载与字节码-图解方法执行流程)_第7张图片
ldc #3

  • 从常量池加载#3数据到操作数栈

  • 注意Short.MAX_VALUE是32767,所以32768 = Short.MAX_VALUE + 1实际是在编译期间计算好的
    【JVM】JVM04(类加载与字节码-图解方法执行流程)_第8张图片
    istore_2

  • 将栈顶数据弹出放入局部变量表的2号槽位

  • 此处可以发现,32768(Short.MAX_VALUE + 1)是在编译期间就已经计算好了的,
    【JVM】JVM04(类加载与字节码-图解方法执行流程)_第9张图片
    【JVM】JVM04(类加载与字节码-图解方法执行流程)_第10张图片

iload_1

  • 将局部变量表中1槽位的值读取到操作数栈

【JVM】JVM04(类加载与字节码-图解方法执行流程)_第11张图片
iload_2

  • 将局部变量表中2槽位的值读取到操作数栈

【JVM】JVM04(类加载与字节码-图解方法执行流程)_第12张图片
iadd

  • 依次弹出操作数栈栈顶的两个数字,进行相加操作,计算完毕后将结果压入操作数栈中

【JVM】JVM04(类加载与字节码-图解方法执行流程)_第13张图片

  • 结果32778被压入栈
    【JVM】JVM04(类加载与字节码-图解方法执行流程)_第14张图片

istore3

  • 将操作数栈顶的元素放入局部变量表的3号槽位

【JVM】JVM04(类加载与字节码-图解方法执行流程)_第15张图片
getstatic #4

  • 到常量池中找到#4,发现是成员变量的引用,它的实际对象存放在堆内存中,通过常量池找到堆中的system对象,将对象的引用放入操作数栈

【JVM】JVM04(类加载与字节码-图解方法执行流程)_第16张图片
【JVM】JVM04(类加载与字节码-图解方法执行流程)_第17张图片
iload_3

  • 将局部变量表中3号槽位的c压入到操作数栈

【JVM】JVM04(类加载与字节码-图解方法执行流程)_第18张图片
【JVM】JVM04(类加载与字节码-图解方法执行流程)_第19张图片
invokevirtual #5

  • 到运行时常量池找到#5
  • 定位到方法区java/io/PrintStream.println:(I)v方法
  • 生成新的栈帧(分配locals、stack等)
  • 传递参数,执行新栈帧中的字节码

【JVM】JVM04(类加载与字节码-图解方法执行流程)_第20张图片

  • 等待栈帧执行完毕,将栈帧弹出并清除main操作数栈内容
  • 【JVM】JVM04(类加载与字节码-图解方法执行流程)_第21张图片
    return
  • 完成main方法调用,弹出main栈帧
  • 程序结束

你可能感兴趣的:(jvm,java,开发语言,后端,jvm,java字节码)