JVM方法调用过程

Posted by     "Eric" on Sunday, December 15, 2019

以Demo类中的main方法为例,讲解字节码在虚拟机运行的过程

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

通过javap反编译后的代码

eric@wuhaodeMacBook-Pro  ~/Desktop/jvM  javap -v Demo
Classfile /Users/eric/Desktop/JVM/Demo.class
  Last modified Nov 11, 2019; size 426 bytes
  MD5 checksum 958b915048427f4b5d8ae3c770331963
  Compiled from "Demo.java"
public class Demo
  minor version: 0
  major version: 54
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #6                          // Demo
  super_class: #7                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #7.#16         // java/lang/Object."<init>":()V
   #2 = Class              #17            // java/lang/Short
   #3 = Integer            32768
   #4 = Fieldref           #18.#19        // java/lang/System.out:Ljava/io/PrintStream;
   #5 = Methodref          #20.#21        // java/io/PrintStream.println:(I)V
   #6 = Class              #22            // Demo
   #7 = Class              #23            // java/lang/Object
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               main
  #13 = Utf8               ([Ljava/lang/String;)V
  #14 = Utf8               SourceFile
  #15 = Utf8               Demo.java
  #16 = NameAndType        #8:#9          // "<init>":()V
  #17 = Utf8               java/lang/Short
  #18 = Class              #24            // java/lang/System
  #19 = NameAndType        #25:#26        // out:Ljava/io/PrintStream;
  #20 = Class              #27            // java/io/PrintStream
  #21 = NameAndType        #28:#29        // println:(I)V
  #22 = Utf8               Demo
  #23 = Utf8               java/lang/Object
  #24 = Utf8               java/lang/System
  #25 = Utf8               out
  #26 = Utf8               Ljava/io/PrintStream;
  #27 = Utf8               java/io/PrintStream
  #28 = Utf8               println
  #29 = Utf8               (I)V
{
  public Demo();
    descriptor: ()V
    flags: (0x0001) 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 1: 0

  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/PrintStream.println:(I)V
        17: return
      LineNumberTable:
        line 3: 0
        line 4: 3
        line 5: 6
        line 6: 10
        line 7: 17
}
SourceFile: "Demo.java"
  1. 字节码文件经过类加载器加载到内存中,其中将字节码文件中的常量池加载到运行时常量池,将方法表的内容加载到方法区(运行时常量池在jdk1.8之前其实也属于方法区,这里只是为了表述方便,将其拆开为两部分),根据字节码文件中方法表中的内容(stack=2, locals=4, args_size=1),分配四个Slot给局部变量(32位数据占1Slot,64位数据占2Slot),操作数栈的最大深度为2 3bYWlT.png

  2. Bipush 10 将常量10推入操作数栈 3bY5m4.png

  3. istore_1 将操作数栈栈顶元素弹出存入局部变量表1的位置 3bYI0J.png

  4. Ldc #3 将运行时常量表中的32768存入操作数栈中(比较小的数字随字节码指令存放在一起,一旦数字的范围超过Short整数的最大值,则会存放在常量池中) 3bYX6O.png

  5. istore_2 将操作栈栈顶元素弹出,保存在局部变量表2的位置 3bYxne.png

  6. iload_1 iload_2这两个指令将局部变量1、2再次加载到了操作数栈中 3btCtI.png

  7. iadd将栈中元素相加,并将结果置于栈顶 3btk1f.png

  8. istore_3 3btEjS.png

  9. getstatic #4 该指令获取类变量的一个引用,System.out这个类变量存放在堆内存中,于是将System.out的引用存放于操作数栈中 3btZng.png

  10. iload3 将局部变量3加载到操作数栈中 3btm7j.png

  11. invokevirtual #5 调用运行时常量池中5所引用的方法,定位到方法区,然后由方法区生成新的栈帧,传递参数,执行新栈帧中的字节码。执行完毕后,将println的栈帧弹出,清楚main操作栈中的内容 3btuAs.png

    3btKNn.png

  12. Return 完成主方法,main的栈帧也弹出