Java虚拟机-如何运行一个程序

2019-08-01  本文已影响0人  贪睡的企鹅

示例程序

源程序

public class Bootstrap {

    public static void main(String[] args) {
        String name = "Louis";
        greeting(name);
    }

    public static void greeting(String name)
    {
        System.out.println("Hello,"+name);
    }
}

javap反编译字节码

Classfile /C:/work/project/juc-in-action/target/classes/jvm/Bootstrap.class
  Last modified 2019-8-1; size 837 bytes
  MD5 checksum 1349bd234c0cad3d90c9236312301d58
  Compiled from "Bootstrap.java"
public class jvm.Bootstrap
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #12.#30        // java/lang/Object."<init>":()V
   #2 = String             #31            // Louis
   #3 = Methodref          #11.#32        // jvm/Bootstrap.greeting:(Ljava/lang/String;)V
   #4 = Fieldref           #33.#34        // java/lang/System.out:Ljava/io/PrintStream;
   #5 = Class              #35            // java/lang/StringBuilder
   #6 = Methodref          #5.#30         // java/lang/StringBuilder."<init>":()V
   #7 = String             #36            // Hello,
   #8 = Methodref          #5.#37         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #9 = Methodref          #5.#38         // java/lang/StringBuilder.toString:()Ljava/lang/String;
  #10 = Methodref          #39.#40        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #11 = Class              #41            // jvm/Bootstrap
  #12 = Class              #42            // java/lang/Object
  #13 = Utf8               <init>
  #14 = Utf8               ()V
  #15 = Utf8               Code
  #16 = Utf8               LineNumberTable
  #17 = Utf8               LocalVariableTable
  #18 = Utf8               this
  #19 = Utf8               Ljvm/Bootstrap;
  #20 = Utf8               main
  #21 = Utf8               ([Ljava/lang/String;)V
  #22 = Utf8               args
  #23 = Utf8               [Ljava/lang/String;
  #24 = Utf8               name
  #25 = Utf8               Ljava/lang/String;
  #26 = Utf8               greeting
  #27 = Utf8               (Ljava/lang/String;)V
  #28 = Utf8               SourceFile
  #29 = Utf8               Bootstrap.java
  #30 = NameAndType        #13:#14        // "<init>":()V
  #31 = Utf8               Louis
  #32 = NameAndType        #26:#27        // greeting:(Ljava/lang/String;)V
  #33 = Class              #43            // java/lang/System
  #34 = NameAndType        #44:#45        // out:Ljava/io/PrintStream;
  #35 = Utf8               java/lang/StringBuilder
  #36 = Utf8               Hello,
  #37 = NameAndType        #46:#47        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #38 = NameAndType        #48:#49        // toString:()Ljava/lang/String;
  #39 = Class              #50            // java/io/PrintStream
  #40 = NameAndType        #51:#27        // println:(Ljava/lang/String;)V
  #41 = Utf8               jvm/Bootstrap
  #42 = Utf8               java/lang/Object
  #43 = Utf8               java/lang/System
  #44 = Utf8               out
  #45 = Utf8               Ljava/io/PrintStream;
  #46 = Utf8               append
  #47 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #48 = Utf8               toString
  #49 = Utf8               ()Ljava/lang/String;
  #50 = Utf8               java/io/PrintStream
  #51 = Utf8               println
{
  public jvm.Bootstrap();
    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   Ljvm/Bootstrap;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=2, args_size=1
         0: ldc           #2                  // String Louis
         2: astore_1
         3: aload_1
         4: invokestatic  #3                  // Method greeting:(Ljava/lang/String;)V
         7: return
      LineNumberTable:
        line 6: 0
        line 7: 3
        line 8: 7
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       8     0  args   [Ljava/lang/String;
            3       5     1  name   Ljava/lang/String;

  public static void greeting(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=1, args_size=1
         0: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: new           #5                  // class java/lang/StringBuilder
         6: dup
         7: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
        10: ldc           #7                  // String Hello,
        12: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        15: aload_0
        16: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        19: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        22: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        25: return
      LineNumberTable:
        line 12: 0
        line 13: 25
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      26     0  name   Ljava/lang/String;
}
SourceFile: "Bootstrap.java"

2 JVM如何运行程序

如果想运行Bootstrap.java 这个程序,首先需要通过javac编译器将其编译成Bootstrap.classJava字节码文件,之后交给Java虚拟机来运行,具体如下几个步骤:

       Class<?> aClass = ClassLoader.getSystemClassLoader().loadClass("jvm.Bootstrap");
image

3 方法运行原理

JVM中线程方法的调用返回对应着方法栈帧在虚拟机栈中的入栈和出栈的过程。一个栈帧描述了方法执行全部流程。

3.1 栈帧的结构

栈帧的结构中主要包含了局部变量,操作数栈动态链接方法返回地址

Code:
      stack=1, locals=2, args_size=1
image
3.2 JVM运行main方法的过程

创建main函数栈帧

JVM为main方法创建一个栈帧(VM Stack),并将其加入虚拟机栈中。

栈帧初始化

image

main函数字节码执行

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=2, args_size=1
         0: ldc           #2                  // String Louis
         2: astore_1
         3: aload_1
         4: invokestatic  #3                  // Method greeting:(Ljava/lang/String;)V
         7: return

//对应Java源码
public static void main(String[] args) {
        String name = "Louis";
        greeting(name);
}         

给局部变量赋值

0: ldc           #2                  // String Louis
2: astore_1

//对应Java源码
String name = "Louis";
image image

调用greeting静态方法

 3: aload_1
 4: invokestatic  #3                  // Method greeting:(Ljava/lang/String;)V
 
 //对应Java源码
 greeting(name);
image image

JVM调用greeting静态方法,会将greeting方法符号引用常量转化为直接引用。直接引用内保存了greeting方法在方法区中内存地址。这里对应到字节码中 greeting。接下来会Code属性第一个要执行的字节码指令位置,开始执行。

3.3 JVM运行greeting方法的过程

创建greeting函数栈帧

JVM为greeting方法创建一个栈帧(VM Stack),并将其加入虚拟机栈中。用以表示对greeting方法的调用。

栈帧初始化

image image

字节码指令执行

 public static void greeting(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=1, args_size=1
         0: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: new           #5                  // class java/lang/StringBuilder
         6: dup
         7: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
        10: ldc           #7                  // String Hello,
        12: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        15: aload_0
        16: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        19: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        22: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        25: return

public static void greeting(String name)
{
        System.out.println("Hello,"+name);
}        

打印"Hello,"+name

image image image image image image image image
上一篇 下一篇

猜你喜欢

热点阅读