【深入理解JVM 一】一个Java程序的执行流程

本文是《深入理解JVM》系列的第一篇,介绍了Java程序从编辑源码到执行的整体流程。首先,程序经历编辑源码、编译生成字节码阶段。接着,JVM加载并执行字节码文件,包括类加载过程、运行字节码指令。在JVM内存模型中,涉及方法区、栈、堆等部分。文章还探讨了IDEA中查看字节码的方式,并详细解析了main方法、构造方法、study方法的执行过程。总结了从源代码到垃圾回收的完整生命周期。
摘要由CSDN通过智能技术生成

本篇是《深入理解JVM》系列博客的第一篇,旨在全局把控,先对整体流程有个认识,然后再分阶段详解。程序从编写到执行整体可以划分为以下几个步骤:编辑源码->编译生成class文件->(加载class文件、运行class字节码文件、垃圾回收),其中后两个步骤都是在jvm虚拟机上执行的,整体的执行流程如下:
在这里插入图片描述

编辑生成源代码

编辑源代码是经历的第一个环节,编辑源代码,就是我们在任何一个工具上编写源代码,可以是记事本,也可以是IDE,这部分相当于我们在IDEA上 新建一个.java的Class 然后写内容,这里我们创建几个类和接口:

//父类Person
public class Person {
    //成员变量
    private String name;
    private int age;
      
    //构造方法
    public Person(int age, String name){
        this.age = age;
        this.name = name;
    }
    //成员方法
    public void run(){

    }
}
//接口IStudy 
public interface IStudy {
     int study(int a, int b);
}

真正的Strudent类,实现接口IStudy 和继承父类Person:

public class Student extends Person implements IStudy {
    //私有静态成员变量
    private static int cnt=5;
    //静态方法块
    static{
        cnt++;
    }
    //私有成员变量
    private String sid;
    //构造方法
    public Student(int age, String name, String sid){
        //继承父类构造方法
        super(age,name);
        this.sid = sid;
    }
    //父类方法重写
    public void run(){

        System.out.println("run()...");

    }
    //实现接口方法
    public int study(int a, int b){
        int c = 10;
        int d = 20;
        return a+b*c-d;
    }
    //成员方法
    public static int getCnt(){
        return cnt;
    }
    
    //方法加载入口
    public static void main(String[] args){

        Student s = new Student(28,"tml","20210201");
        //接口方法调用
        s.study(5,6);
        //成员方法调用
        Student.getCnt();
        //父类重写方法调用 
        s.run();

    }

}

可以从文件路径看到已经有三个Java文件生成了:
在这里插入图片描述

编译生成字节码

编译的过程就是生成.class字节码文件,输入命令javac Student.java将该源码文件.java编译生成.class字节码文件。由于在源码文件中定义了两个类,一个接口,所以生成了3个.clsss文件。
在这里插入图片描述
字节码文件是真正实现Java语言跨平台的基石,JVM运行的是class字节码文件,只要是这种格式的文件就行

  • 各种不同平台的虚拟机都统一使用这种相同的程序存储格式 跨平台
  • 其他语言编写的源码编译成字节码文件,交给jvm去运行,只要是合法的字节码文件,JVM都会正确地跑起来。 跨语言

所以其实可以看的出它实现了跨平台和跨语言,用一张图可以描述清楚
在这里插入图片描述

在类文件夹目录下可以执行类问题,用命令javap -c Student 执行类class文件结构如下 :

"C:\Program Files\Java\jdk1.8.0_251\bin\javap.exe" -c Student.class
Compiled from "Student.java"
public class com.company.Student extends com.company.Person implements com.company.IStudy {
  public com.company.Student(int, java.lang.String, java.lang.String);
    Code:
       0: aload_0
       1: iload_1
       2: aload_2
       3: invokespecial #1                  // Method com/company/Person."<init>":(ILjava/lang/String;)V
       6: aload_0
       7: aload_3
       8: putfield      #2                  // Field sid:Ljava/lang/String;
      11: return

  public void run();
    Code:
       0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #4                  // String run()...
       5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return

  public int study(int, int);
    Code:
       0: bipush        10
       2: istore_3
       3: bipush        20
       5: istore        4
       7: iload_1
       8: iload_2
       9: iload_3
      10: imul
      11: iadd
      12: iload         4
      14: isub
      15: ireturn

  public static int getCnt();
    Code:
       0: getstatic     #6                  // Field cnt:I
       3: ireturn

  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class com/company/Student
       3: dup
       4: bipush        28
       6: ldc           #8                  // String tml
       8: ldc           #9                  // String 20210201
      10: invokespecial #10                 // Method "<init>":(ILjava/lang/String;Ljava/lang/String;)V
      13: astore_1
      14: aload_1
      15: iconst_5
      16: bipush        6
      18: invokevirtual #11                 // Method study:(II)I
      21: pop
      22: invokestatic  #12                 // Method getCnt:()I
      25: pop
      26: aload_1
      27: invokevirtual #13                 // Method run:()V
      30: return

  static {};
    Code:
       0: iconst_5
       1: putstatic     #6                  // Field cnt:I
       4: getstatic     #6                  // Field cnt:I
       7: iconst_1
       8: iadd
       9: putstatic     #6                  // Field cnt:I
      12: return
}

Process finished with exit code 0

可以看到字节码文件存放了这个类的各种信息:字段、方法、父类、实现的接口等各种信息

IDEA配置字节码查看方式

在IDEA的Settings里进行相关配置即可,配置截图如下:
在这里插入图片描述
填写的相关属性信息如下:

  1. 其中Name为工具的名称,可以随意填写,这里我命名:ShowByteCode
  2. Program表示你所使用的程序,这里我们选择jdk里面的javap工具。点击文件夹找到路径即可,我的路径为:C:\Program Files\Java\jdk1.8.0_251\bin\javap.exe
  3. Arguments表示你使用Program程序时跟随的参数,这里直接填写-c $FileNameWithoutExtension$.class
  4. Working directory表示当前工作目录,这里直接填写:$OutputPath$\$FileDirRelativeToSourcepath$

配置好以上信息在对应的类右键查看字节码即可:
在这里插入图片描述

IDEA集成Jclasslib

File -> setting -> plugins路径下直接安装jclasslib:
在这里插入图片描述
重启后直接打开view 查看:
在这里插入图片描述
可以直观的看到每个方法调用时局部变量表的内容以及操作数栈的操作,如果用Jclasslib来查看字节码比IDEA集成的看起来更清晰一些,内容如下,

// class version 52.0 (52)
// access flags 0x21
public class com/company/Student extends com/company/Person implements com/company/IStudy {

  // compiled from: Student.java

  // access flags 0xA
  private static I cnt

  // access flags 0x2
  private Ljava/lang/String; sid

  // access flags 0x1
  public <init>(ILjava/lang/String;Ljava/lang/String;)V
   L0
    LINENUMBER 15 L0
    ALOAD 0
    ILOAD 1
    ALOAD 2
    INVOKESPECIAL com/company/Person.<init> (ILjava/lang/String;)V
   L1
    LINENUMBER 16 L1
    ALOAD 0
    ALOAD 3
    PUTFIELD com/company/Student.sid : Ljava/lang/String;
   L2
    LINENUMBER 17 L2
    RETURN
   L3
    LOCALVARIABLE this Lcom/company/Student; L0 L3 0
    LOCALVARIABLE age I L0 L3 1
    LOCALVARIABLE name Ljava/lang/String; L0 L3 2
    LOCALVARIABLE sid Ljava/lang/String; L0 L3 3
    MAXSTACK = 3
    MAXLOCALS = 4

  // access flags 0x1
  public run()V
   L0
    LINENUMBER 21 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "run()..."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L1
    LINENUMBER 23 L1
    RETURN
   L2
    LOCALVARIABLE this Lcom/company/Student; L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1

  // access flags 0x1
  public study(II)I
   L0
    LINENUMBER 26 L0
    BIPUSH 10
    ISTORE 3
   L1
    LINENUMBER 27 L1
    BIPUSH 20
    ISTORE 4
   L2
    LINENUMBER 28 L2
    ILOAD 1
    ILOAD 2
    ILOAD 3
    IMUL
    IADD
    ILOAD 4
    ISUB
    IRETURN
   L3
    LOCALVARIABLE this Lcom/company/Student; L0 L3 0
    LOCALVARIABLE a I L0 L3 1
    LOCALVARIABLE b I L0 L3 2
    LOCALVARIABLE c I L1 L3 3
    LOCALVARIABLE d I L2 L3 4
    MAXSTACK = 3
    MAXLOCALS = 5

  // access flags 0x9
  public static getCnt()I
   L0
    LINENUMBER 32 L0
    GETSTATIC com/company/Student.cnt : I
    IRETURN
    MAXSTACK = 1
    MAXLOCALS = 0

  // access flags 0x9
  public static main([Ljava/lang/String;)V
   L0
    LINENUMBER 38 L0
    NEW com/company/Student
    DUP
    BIPUSH 28
    LDC "tml"
    LDC "20210201"
    INVOKESPECIAL com/company/Student.<init> (ILjava/lang/String;Ljava/lang/String;)V
    ASTORE 1
   L1
    LINENUMBER 40 L1
    ALOAD 1
    ICONST_5
    BIPUSH 6
    INVOKEVIRTUAL com/company/Student.study (II)I
    POP
   L2
    LINENUMBER 42 L2
    INVOKESTATIC com/company/Student.getCnt ()I
    POP
   L3
    LINENUMBER 44 L3
    ALOAD 1
    INVOKEVIRTUAL com/company/Student.run ()V
   L4
    LINENUMBER 46 L4
    RETURN
   L5
    LOCALVARIABLE args [Ljava/lang/String; L0 L5 0
    LOCALVARIABLE s Lcom/company/Student; L1 L5 1
    MAXSTACK = 5
    MAXLOCALS = 2

  // access flags 0x8
  static <clinit>()V
   L0
    LINENUMBER 5 L0
    ICONST_5
    PUTSTATIC com/company/Student.cnt : I
   L1
    LINENUMBER 8 L1
    GETSTATIC com/company/Student.cnt : I
    ICONST_1
    IADD
    PUTSTATIC com/company/Student.cnt : I
   L2
    LINENUMBER 9 L2
    RETURN
    MAXSTACK = 2
    MAXLOCALS = 0
}

JVM加载执行字节码文件

在命令行中输入java Student这个命令,就启动了一个java虚拟机,然后加载Student.class字节码文件到内存,然后运行内存中的字节码指令了。这部分的操作就相当于我们在IDEA这样的ide上 点击运行按钮。整个字节码class文件执行的整体宏观如图所示:
在这里插入图片描述
虚拟机JVM负责核心的加载.class文件、将.class文件转为机器码,最终执行机器码。JVM的功能模块主要包括类加载器、执行引擎垃圾回收系统。同时JVM有自己的内存模型。

JVM内存模型

JVM中把内存分为方法区、Java栈、Java堆、本地方法栈、PC寄存器 5部分数据区域:

  1. 方法区:用于存放类、接口、常量以及静态变量等元数据信息,加载进来的字节码数据都存储在方法区
  2. 虚拟机栈 :执行引擎运行字节码时的运行时内存区,采用栈帧的形式保存每个方法的调用运行数据
  3. 本地方法栈:执行引擎调用本地方法时的运行时内存区
  4. Java堆:运行时数据区,各种对象一般都存储在堆上
  5. PC寄存器(程序计数器):功能如同CPU中的PC寄存器,指示要执行的字节码指令。

这部分内容在 Jvm运行时内存分析这篇blog详细解析

类加载过程

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化五个阶段,其中验证、准备、解析三个部分统称链接
在这里插入图片描述

各个阶段需要对代码操作内容如下:

  1. 加载阶段
    1)类加载器会在指定的classpath中找到Student.class(通过类的全限定名)这个文件,然后读取字节流中的数据,将其存储在方法区中。
    2)类加载器根据Student.class的信息建立一个Class对象,这个对象比较特殊,一般也存放在方法区中,用于作为运行时访问Student类的各种数据的接口。
  2. 验证阶段:必要的验证工作,格式、语义等
  3. 准备阶段: 为Student中的静态字段分配内存空间,也是在方法区中,并进行零初始化,即数字类型初始化为0,boolean初始化为false,引用类型初始化为null等。private static int cnt=5; 此时,并不会执行赋值为5的操作,而是将其初始化为0。
  4. 解析阶段:由于已经加载到内存了,所以原来字节码文件中存放的部分方法、字段等的符号引用可以解析为其在内存中的直接引用了,而不一定非要等到真正运行时才进行解析。
  5. 初始化阶段:初始化阶段是执行类构造器()方法的过程,是真正意义上开始执行阶段

类加载过程中主要是将class文件(准确地讲,应该是类的二进制字节流)加载到虚拟机内存中,真正执行字节码的操作,在加载完成后才真正开始

运行字节码指令

执行引擎找到main这个入口方法,执行其中的字节码指令,这里就依赖到了Java栈,也就是虚拟机栈,其结构如下:
在这里插入图片描述
每一个方法从调用开始至执行完成的过程,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧(Current Stack Frame),与这个栈帧相关联的方法称为当前方法(Current Method)。执行引 擎运行的所有字节码指令都只针对当前栈帧进行操作

  • 当前正在运行的方法的栈帧位于栈顶,当前方法返回,则当前方法对应的栈帧出栈,当前方法的调用者的栈帧变为栈顶
  • 当前方法的方法体中若是调用了其他方法,则为被调用的方法创建栈帧,并将其压入栈顶。简单查看我们上述方法的运行过程:

注意当存在方法调用关系时遵循以上两个原则

main方法执行

main方法对应的下面是我们执行的代码:

  //方法加载入口
    public static void main(String[] args){

        Student s = new Student(28,"tml","20210201");
        //接口方法调用
        s.study(5,6);
        //成员方法调用
        Student.getCnt();
        //父类重写方法调用 
        s.run();
    }

其对应的字节码指令如下:

  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class com/company/Student
       3: dup
       4: bipush        28
       6: ldc           #8                  // String tml
       8: ldc           #9                  // String 20210201
      10: invokespecial #10                 // Method "<init>":(ILjava/lang/String;Ljava/lang/String;)V
      13: astore_1
      14: aload_1
      15: iconst_5
      16: bipush        6
      18: invokevirtual #11                 // Method study:(II)I
      21: pop
      22: invokestatic  #12                 // Method getCnt:()I
      25: pop
      26: aload_1
      27: invokevirtual #13                 // Method run:()V
      30: return

首先会在虚拟机栈中为main方法创建栈帧,局部变量表长度为2,slot0存放参数args,slot1存放局部变量Student s,操作数栈最大深度为5:
在这里插入图片描述

然后执行new#7指令,在java堆中创建一个Student对象,并将其引用值放入main栈帧中
在这里插入图片描述
最后初始化一个对象所需的参数入操作数栈(通过实例构造的方式):

  1. up:复制栈顶的值,然后将复制的结果入操作数栈。
  2. bipush 28:将单字节常量值28入操作数栈。
  3. ldc #8:将#8这个常量池中的常量即tml取出,并入操作数栈。
  4. ldc #9:将#9这个常量池中的常量即20210201取出,并入操作数栈。

入栈后的整体效果如下

在这里插入图片描述

Strudent构造方法执行

invokespecial #10:调用#10这个常量所代表的方法,即Student.<init>()这个方法,这步是为了初始化对象s的各项值,<init>()方法,是编译器将调用父类的<init>()的语句、构造代码块、实例字段赋值语句,以及自己编写的构造方法中的语句整合在一起生成的一个方法。保证调用父类的<init>()方法在最开头,自己编写的构造方法语句在最后,而构造代码块及实例字段赋值语句按出现的顺序按序整合到<init>()方法中。此时需注意:上边从dup到ldc #9这四条指令向栈中添加了4个数据,而Student.()方法刚好也需要4个参数:

 //构造方法
    public Student(int age, String name, String sid){
        //继承父类构造方法
        super(age,name);
        this.sid = sid;
    }

其对应的字节码文件为:

 public com.company.Student(int, java.lang.String, java.lang.String);
    Code:
       0: aload_0
       1: iload_1
       2: aload_2
       3: invokespecial #1                  // Method com/company/Person."<init>":(ILjava/lang/String;)V
       6: aload_0
       7: aload_3
       8: putfield      #2                  // Field sid:Ljava/lang/String;
      11: return

虽然定义中只显式地定义了传入3个参数,而实际上会隐含传入一个当前对象的引用作为第一个参数,所以四个参数依次为this,age,name,sid。上面的4条指令刚好把这四个参数的值依次入栈,进行参数传递,然后调用了Student.<init>()方法,会创建该方法的栈帧,并入栈。栈帧中的局部变量表的第0到4个slot分别保存着入栈的那四个参数值。创建Studet.<init>()方法的栈帧:
在这里插入图片描述

Student.<init>()方法中的字节码指令如下:

  1. aload_0:将局部变量表slot0处的引用值入操作数栈

  2. aload_1:将局部变量表slot1处的int值入操作数栈

  3. aload_2:将局部变量表slot2处的引用值入操作数栈
    在这里插入图片描述

  4. invokespecial #1:调用Person.<init>()方法,同调用Student.<init>过程类似,创建栈帧,将三个参数的值存放到局部变量表等,并且给堆上的对象赋值
    在这里插入图片描述

  5. Person.<init>()返回之后,用于传参的操作数栈的3个值被回收了, Person栈帧的使命完成。

  6. aload_0:将slot0处的引用值入栈,也就是父类构造好的引用。

  7. aload_3:将slot3处的引用值入栈,也就是子类独有的参数sid。

  8. putfield #2:将当前栈顶的值”20210201”赋值给0x2222所引用对象的sid字段,然后两个参数出栈。

  9. return:返回调用方即main()方法,当前方法栈帧出栈,main栈帧上操作数栈上使用的几个slot销毁,只保留了最底部的引用0x222
    在这里插入图片描述

回到main方法中

重新回到main()方法中,继续执行下面的字节码指令:

  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class com/company/Student
       3: dup
       4: bipush        28
       6: ldc           #8                  // String tml
       8: ldc           #9                  // String 20210201
      10: invokespecial #10                 // Method "<init>":(ILjava/lang/String;Ljava/lang/String;)V
      13: astore_1
      14: aload_1
      15: iconst_5
      16: bipush        6
      18: invokevirtual #11                 // Method study:(II)I
      21: pop
      22: invokestatic  #12                 // Method getCnt:()I
      25: pop
      26: aload_1
      27: invokevirtual #13                 // Method run:()V
      30: return

astore_1:将当前栈顶引用类型的值赋值给slot1处的局部变量,然后出栈。
在这里插入图片描述

接下来继续执行main方法的相关指令:

  1. aload_1:slot1处的引用类型的值入栈,也就是要开始使用s对象的方法,所以先将引用入栈
  2. iconst_5:将常数5入栈,int型常数只有0-5有对应的iconst_x指令
  3. bipush 6:将变量6入栈
  4. invokevirtual #11:调用虚方法study(),这个方法是重写的接口中的方法,需要动态分派,所以使用了invokevirtual指令。
    在这里插入图片描述

Study方法的执行

构造方法执行完成后,即顺序执行study方法的调用,代码如下:

 //实现接口方法
    public int study(int a, int b){
        int c = 10;
        int d = 20;
        return a+b*c-d;
    }

字节码如下:


  public int study(int, int);
    Code:
       0: bipush        10
       2: istore_3
       3: bipush        20
       5: istore        4
       7: iload_1
       8: iload_2
       9: iload_3
      10: imul
      11: iadd
      12: iload         4
      14: isub
      15: ireturn

最大栈深度3,局部变量表5
在这里插入图片描述

字节码指令执行如下:

  1. bipush 10:将10入栈
  2. istore_3:将栈顶的10赋值给slot3处的int局部变量,即c,出栈。
  3. bipush 20:将20入栈
  4. istore 4:将栈顶的20赋值给slot4处的int局部变量,即d,出栈。上面4条指令,完成对c和d的赋值工作。iload_1、iload_2、iload_3这三条指令将slot1、slot2、slot3这三个局部变量入栈:
    在这里插入图片描述
  5. imul:将栈顶的两个值出栈,相乘的结果入栈,也就是计算b*c:
    在这里插入图片描述
  6. iadd:将当前栈顶的两个值出栈,相加的结果入栈,也就是计算a+b*c
  7. iload 4:将slot4处的int型的局部变量入栈,也就是将d入栈
  8. isub:将栈顶两个值出栈,相减结果入栈,也就是计算a+b*c-d:
    在这里插入图片描述
  9. ireturn:将当前栈顶的值返回到调用方,到这里为止study方法执行完毕,study栈帧出虚拟机栈,main栈帧上的操作数栈清空,方法继续向下执行。

以上study的方法就执行完成了。

回到main方法中

重新回到main()方法中,继续执行下面的字节码指令:

  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class com/company/Student
       3: dup
       4: bipush        28
       6: ldc           #8                  // String tml
       8: ldc           #9                  // String 20210201
      10: invokespecial #10                 // Method "<init>":(ILjava/lang/String;Ljava/lang/String;)V
      13: astore_1
      14: aload_1
      15: iconst_5
      16: bipush        6
      18: invokevirtual #11                 // Method study:(II)I
      21: pop
      22: invokestatic  #12                 // Method getCnt:()I
      25: pop
      26: aload_1
      27: invokevirtual #13                 // Method run:()V
      30: return

下面的字节码指令就不再重复画图示意了:

  1. invokestatic #12 调用静态方法getCnt()不需要传任何参数
  2. pop:getCnt()方法有返回值,将其出栈
  3. aload_1:将slot1处的引用值入栈
  4. invokevirtual #13:调用0x2222对象的run()方法,重写自父类的方法,需要动态分派,所以使用invokevirtual指令
  5. return:main()返回,程序运行结束。

这样整体的main方法也执行完毕,整个程序调用完毕。

总结

总结而言,从一个Java程序被编写,最后一直到创建的对象被垃圾回收,全流程包括以下几步,加粗部分为本系列接下来的blog重点讲解内容:

  1. 编辑生成源代码.java文件
  2. 编译(javac编译和jit编译)生成字节码文件
  3. 类文件被加载到虚拟机(类Class文件结构,虚拟机运行时内存分析,类加载机制
  4. 虚拟机执行二进制字节码(虚拟机字节码执行系统
  5. 垃圾回收(JVM垃圾回收机制

虚拟机发挥作用的部分从第3步到第5步之间:

  1. 类加载阶段:一个类文件首先加载到方法区,一些符号引用被解析(静态解析)为直接引用或者等到运行时分派(动态绑定),经过一系列的加载过程(class文件的常量池被加载到方法区的运行时常量池,各种其它的静态存储结构被加载为方法区运行时数据解构等等),程序通过Class对象来访问方法区里的各种类型数据
  2. 字节码执行阶段:当加载完之后,程序发现了main方法,也就是程序入口,那么程序就在栈里创建了一个栈帧,逐行读取方法里的代码所转换为的指令,而这些指令大多已经被解析为直接引用了,那么程序通过持有这些直接引用使用指令去方法区中寻找变量对应的字面量来进行方法操作。
  3. JVM垃圾回收阶段:操作完成后方法返回给调用方,该栈帧出栈。内存空间被GC回收,堆里被new的那些也就被垃圾回收机制GC了。

以上就是整个Java程序的生命周期。

JVM中类加载的过程详解
程序员资料站
01-13 587
类从被加载到虚拟机内存中开始,到卸载出内存,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initiallization)、使用(Using)和卸载(Unloading)这7个阶段。其中验证、准备、解析3个部分统称为连接(Linking)
JVM学习之路(一)——java程序执行流程
u012556994的博客
07-28 836
JVM这个庞然大物,平用不到,也就不愿意去学。现在面试经常被问到,不得不厚着脸皮去学。那由表及里,慢慢学吧。 一、java程序执行流程 本来画图更清晰的,但间紧迫,先在这里占个坑,后面补图。 ①编写.java源文件 ②用java编译器将源文件编译为.class的字节码文件 ③通过“java 类名”的方式执行,在执行过程中会进行后续流程(④⑤⑥⑦) ④根据系统版本去找到对应的JVM配...
JVMJVM的组成与执行流程
最新发布
loss_rose777的博客
07-31 1012
全网关于JVM的组成和运行原理最清楚的一篇文章,如果你对JVM组成和运行流程有问题看这一篇文章完全能解决你的问题
java技术--JVM程序执行流程(02)
qq591009234的博客
05-25 375
1.程序执行流程我把它划分为以下几个步骤 (1)编辑源码、编译生成class文件、加载class文件、运行class字节码文件 (2)其中后两个步骤都是在jvm虚拟机上执行的 2.编译源代码 (1)编译源代码是经历的第一个环节 <1>就是在任何一个工具上编写源代码,可以是记事本,最后命名为Student.java <2>相当于在myeclipse这样的ide上新建一个.java的Class然后写内容 (2)源码文件示例Person.java public class
jvm运行机制
panzm_csdn的博客
06-10 539
JVM启动流程1.java虚拟机启动的命令是通过java +xxx(类名,这个类中要有main方法)或者javaw启动的。2.执行命令后,系统第一步做的就是装载配置,会在当前路径中寻找jvm的config配置文件。3.找到jvm的config配置文件之后会去定位jvm.dll这个文件。这个文件就是java虚拟机的主要实现。4.当找到匹配当前版本的jvm.dll文件后,就会使用这个dll去初始化jv...
一文带你吃透Java代码执行过程:JVM加载字节码+解释执行+编译执行
2401_83384536的博客
03-12 1692
前本节简单介绍Java代码执行过程,JVM执行Java代码所做的工作,以及JVM是如何设计的。Java代码执行的过程简单可以分为以下几步:1)Java代码被编译成字节码。2)(可选)字节码被AOT编译器编译成可执行文件(该功能在JDK 17中被废弃)。3)通过JVM执行字节码或者可执行文件。JVM作为一个程序,主要包含以下功能:1)JVM加载并解析字节码,或者JVM加载可执行文件,并解析可执行文件。
一次性精通JVM JAVA虚拟机
06-17
第1章 基础入门,从JVM是什么开始讲起,理解JDK、JRE、JVM的关系,java的编译流程和执行流程,让您轻松入门。 第2章 字节码文件,深入剖析字节码文件的全部组成结构,以及javap和jbe可视化反解析工具的使用。 第3章 ...
deepinJvm-zzm:周志明,深入理解JVM的源代码
03-17
首先,Java虚拟机是Java程序执行的平台,它负责将编译后的字节码转换为机器码,实现了跨平台的“一次编写,到处运行”特性。JVM主要由以下几个部分组成: 1. 类加载器:负责加载类文件,包括启动类加载器、扩展类...
深入学习JVMJava虚拟机)内核教程
09-12
- **应用场景**:理解Java字节码文件格式有助于进行更底层的Java程序开发和调试。 #### 10. 字节码执行 - **概述**:JVM执行Java程序的过程实际上就是解释执行字节码的过程。 - **执行流程**: - **加载**:将类...
JVM.rar_java 工作流_java 虚拟机_jvm_jvm hook_虚拟机 Java
09-14
深入理解JVM的工作流程之前,我们首先需要知道Java程序是如何被编译和运行的。Java源代码(.java文件)通过Java编译器(javac)被编译成Java字节码(.class文件),这些字节码可以在任何安装了JVM的平台上运行,...
类在JVM中的执行过程
younger的博客
04-28 3458
java源文件(.java)被编译成字节码(.class)文件后,启用命令java Demo,就会调用Demo类的main()方法来启动java虚拟机(jvm)。即JVM加载到内存后,就调用Demo的main()方法开始它的工作。JVM将按特定顺序做三件事:加载、链接和初始化。
java程序JVM中是如何运行的?
weixin_42212173的博客
02-16 1490
JVM的内存模型 JVM内存是人为根据不同内存空间的存储特点以及存储的数据进行划分的。 程序计数器:当前线程所执行字节码行号指示器 本地方法栈:为虚拟机使用的native方法服务 Java虚拟机栈:描述Java方法执行的内存模型,每个方法被执行候都会同创建一个栈帧用于存储局部变量表,操作栈,动态链接,方法出口等信息。每一个方法会创建一个栈帧,栈帧存放了当前方法的数据信息(局部变量),当方法执行完毕栈帧就被销毁。 Java堆:被所有线程共享的一块内存区域,在虚拟机启动创建,所有的对象实例
JVM的内存及使用java运行类过程
HYA2464336555的博客
04-09 900
JVM的内存可以分: 1、栈:方法运行,会被放到栈中 2、堆:保存对象 3、方法区:存放着类,类里的方法 4、本地方法区:本地方法(由C、C++编写的方法) 5、程序计数器:记录当前程序运行到那个位置 当使用JAVA运行一个 1)由JRE中的ClassLoader(类加载器),将类的信息交给JVM 2)JVM会将类的信息保存在方法区中 3)JVM启动主线程,将main方法压入栈中 4)程序计数器,记录main方法中执行的顺序 5)如果main中调用了其他方法,将被调用的方法压入栈
JVM -JAVA程序执行流程1
qq_27803495的博客
07-29 134
1.子类继承父类新建对象,内存分配 1.1子类存有父类对子类的可见信息 1.2子类堆中存有指向父类堆的一个指针 1.3子类堆中有一块区域存放父类信息,子父类中同一变量在堆中位置不同,在方法区子类存有父类方法,若子类复写了该方法,则子类的方法区中父类所占区域的方法会被覆盖。子类里有一个区域放的父类的实例,子类内存区里有一个this指针,指向了这个内存区里包括的父类实例区,当把引用付给父类,是把子类内存区里面的父类实例区域的引用给了父类的实例. 继承的基本概念: (1)Java不...
java基础】JVM执行流程
qq_43654226的博客
09-11 2320
写在最前,本人也只是个大三的学生,如果你发现任何我写的不对的,请在评论中指出。   对于我而言,可以把JVM的整体结构分为三层: 上层:前端编译器(IDEA、VSCODE等) → Class Files → 类装载器子系统 中层:运行数据区域(以JDK1.8为准):元空间、 堆、虚拟机栈、本地方法栈、程序计数器 下层:执行引擎(称为后端编译器,主要用于将字节码文件识别为机器指令)、本地方法接口、本地方法库 了解了JVM的整体结构,我们以一段代码为切入点,了解一下JVM执行机制: public c.
Java程序执行流程JVM
消极的人永远是对的,积极的人选择勇往直前
08-03 951
首先了解JVM架构:https://mp.csdn.net/console/editor/html/107181269
java程序JVM中的运行顺序:
Panda_sit_up的博客
11-20 846
java程序JVM中的运行顺序: 1.加载主方法的class文件Main.class进入方法区,为 static main()分配执行入口(即内存空间)。 2.发现static main()是主方法,则主方法加载入栈。 3.加载一般类文件A.class进入方法区,给有static修 饰的静态变量分配内存空间,给static修饰的静态方 法分配执行入口(即地址)。 4.在堆中实例化对
jvm用于运行 java_Java程序jvm中运行过程
weixin_39699670的博客
02-13 413
以下内容是从任小龙讲师课堂笔记中整理。JVM内存模型如上图JVM内存是人为根据不同内存空间的存储特点以及存储的数据进行划分的。程序计数器:当前线程所执行字节码行号指示器本地方法栈:为虚拟机使用的native方法服务Java虚拟机栈:描述Java方法执行的内存模型,每个方法被执行候都会同创建一个栈帧用于存储局部变量表,操作栈,动态链接,方法出口等信息。每一个方法会创建一个栈帧,栈帧存放了当前...
写文章

热门文章

  • 【年度总结系列 2019】2019 时不我与 25844
  • 【从Java到C#系列 一】VS2017的安装 25739
  • 【解决方案 十八】连接已重置怎么办 24428
  • 【解决方案 二】---设置mysql5.7编码集为utf8mb4 22164
  • 【解决方案 七】---Git Merge时“交换文件.MERGE_MSG.swp已经存在”的问题 18693

分类专栏

  • Java 程序员技术栈 付费 28篇
  • Java 语言生态地图 付费 10篇
  • Java SE核心 付费
  • Java 数据结构与算法 付费 12篇
  • Java 虚拟机 付费 8篇
  • Java 核心基础 13篇
  • Java 工具与集合类 2篇
  • Java 高级特性&新特性 4篇
  • Java 并发编程 14篇
  • Java Web编程 15篇
  • Java Web框架
  • MyBatis 8篇
  • Spring 9篇
  • Spring MVC 8篇
  • Spring Boot 14篇
  • RPC框架 4篇
  • 数据库
  • MySQL 16篇
  • Cassandra 3篇
  • 计算机基础
  • 操作系统 2篇
  • 计算机网络 7篇
  • 高频算法题训练 56篇
  • 数据结构
  • 数组 4篇
  • 链表 9篇
  • 3篇
  • 队列 3篇
  • 二叉树 11篇
  • 字符串 5篇
  • 哈希表 2篇
  • 算法思维 3篇
  • 排序算法 3篇
  • 二分查找 5篇
  • 搜索算法 1篇
  • 贪心算法 1篇
  • 回溯算法 4篇
  • 动态规划 5篇
  • 分布式服务与中间件
  • 分布式系统 3篇
  • Redis 29篇
  • ElasticSearch 12篇
  • Kafka 10篇
  • Docker&Kubernetes 7篇
  • 生产问题排查 4篇
  • 思想、原则、规范、实践
  • 从零开始学架构 6篇
  • 架构、场景、中间件每日一问 8篇
  • 软件设计模式 41篇
  • 领域驱动设计(DDD) 8篇
  • 编程规范&代码管理 13篇
  • 技术问题与解决方案 38篇
  • 工作中问题解决实践 10篇
  • 智商、情商、逆商、财商
  • 项目流程&技术管理 6篇
  • 逻辑化思维训练 3篇
  • 投资理财知识 23篇
  • 总结、规划、闲谈、讨论
  • 规划&总结&毕业N年系列 19篇
  • 程序人生闲谈琐聊 24篇
  • 话题讨论与项目调研 2篇
  • C#技术合集 49篇

最新评论

  • 【MySQL数据库原理 零】MySQL数据库原理看这一篇就够了

    ghcnbsg: 不对劲啊,这比我论文还要详尽的文章怎么就没人看呢

  • 【Spring MVC学习笔记 七】深入理解SpringMVC拦截器原理

    java架构师uuid(): 过滤器在初始化时候init方法只会在生命周期中执行一次,但是其中的doFilter方法会在每次请求中都会执行,并不是在你说的一个实例只能被调用一次,如果只能被调用一次,那岂不是后来的请求都无法被拦截,如何达到验证、日志、字符串过滤的功能?

  • 【系统架构设计 每日一问】四 如何对关系型数据库及NoSql数据库选型

    小王毕业啦: 博主的文章真的让我眼前一亮,对于数据库选型这个话题,我以前总是感觉一知半解,但是在博主的详细解读下,我终于对这个领域有了更深入的了解。博主的细节描写非常到位,让我感受到了博主在这个领域的深厚功底,对于系统架构设计也有了更清晰的认识。期待博主未来能够持续分享更多干货文章,让我们读者都能够从中受益。同时,也希望能够得到博主的指导,一同进步。非常感谢博主的辛苦分享和支持!

  • 【解决方案 十二】一文彻底解决文件格式判别问题

    qq_33766275: 有一个叫trid的软件,靠检索文件开头是否是“PK”,同时内部是否有“DOCUMENT.XML.RELS”“CONTENT_TYPES”“_RELS”“WORD”等字符串来区分zip和docx

  • 【生产问题排查 二】一次内存泄露排查-MAT使用指南

    JAVA菜鸟程序员: 大佬,堆栈信息是从哪里点进去的?

大家在看

  • java计算机毕业设计玩具租借系统(开题+程序+论文)
  • java+vue计算机毕设二手交易平台管理系统【源码+开题+论文+程序】
  • 风灵月影白屏怎么回事,风灵月影白屏的原因及解决办法详解 798
  • 通过Python代码发送量化交易信号邮件通知 1115
  • 机器学习04-逻辑回归(python)-02原理与损失函数 545

最新文章

  • 【领域驱动设计 打通DDD最小闭环】三 模型的建立-领域建模
  • 【领域驱动设计 打通DDD最小闭环】二 模型的建立-业务事件风暴
  • 【领域驱动设计 打通DDD最小闭环】一 DDD的开发流程
2024
08月 3篇
07月 10篇
06月 3篇
05月 3篇
04月 1篇
03月 4篇
02月 16篇
01月 9篇
2023年72篇
2022年69篇
2021年133篇
2020年81篇
2019年63篇
2018年45篇
2017年99篇
2016年3篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

存在morning

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或 充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家玻璃钢雕塑承德周口玻璃钢卡通雕塑厂家电话温州商场美陈市场报价岳麓玻璃钢花盆花器九江仿铜西式玻璃钢雕塑玻璃钢艺术雕塑售价青海玻璃钢博物馆雕塑商场美陈批发价晋城学校玻璃钢仿铜雕塑公司淮安玻璃钢人物雕塑批发吉林玻璃钢卡通人物雕塑铜陵玻璃钢雕塑生产厂家玻璃钢雕塑正确摆放息烽玻璃钢雕塑制作电话一家三口玻璃钢仿铜人物雕塑优质的玻璃钢雕塑定制珠海商场玻璃钢动物雕塑许昌玻璃钢浮雕景观雕塑厂家菏泽水景玻璃钢卡通雕塑公司曲阳玻璃钢彩绘马雕塑阜阳商场美陈费用济宁卡通玻璃钢雕塑厂家售卖商场美陈驻马店不锈钢玻璃钢仿铜雕塑黑龙江玻璃钢广场雕塑厂家邢台玻璃钢雕塑找哪家德阳玻璃钢动物雕塑河南玻璃钢卡通雕塑橘子厂家惠州玻璃钢雕塑供应商玻璃钢雕塑技工招聘香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化