返回顶部

JVM专题学习之JVM基础知识以及类加载步骤(一)

JVM的基础知识

Java程序的执行过程

java文件->编译器->class文件(字节码)->JVM->机器码
java程序执行过程大致如下:
img

JVM、JRE、JDK三者关系

jvm<jre<jdk
1、JVM:java虚拟机。
作用:保证java语言跨平台
2.JRE:java运行环境 JRE=java虚拟机+核心类库。
作用:java程序的运行环境。
3、JDK :java开发工具集。JDK=JRE+java开发工具。
作用:java程序的开发环境。
三者关系如下图所示:
img

Java语言为什么跨平台

Java跨平台特性的就是基于JVM,如下图所示:
img

Java虚拟机规范

Java虚拟机规范,目前我们jdk使用的规范都是Hotspot(Java HotSpot(TM))
当然,有很多大厂需要对Java虚拟机规范进行定制化比如:TaobaoVM(定制化)
img

Java程序是如何运行起来的

我们将以下图为整体脉络,逐一丰富细节。
img

类加载的机制

首先我们在讲上面这张图的时候,我们应该了解一个知识点就是java类加载的机制。

什么时候去加载?

java加载的时机是采用懒加载的方式,比如一个jar包有100个类,我们是用到哪些类就加载哪个类而不是全部加载。

加载的完整步骤有哪些?

完整步骤如下图所示:
img

1.加载

  • 通过一个类的全限定名(包名+类名)来获取定义此类的二进制字节流。
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

2.验证

验证阶段主要是出于JVM的安全性考虑

  • 文件格式验证
    1.class文件是否符合规范
    说白了就是是否以魔数0xCAFEBABE开头,那么什么是魔数呢?

    魔数这个词在不同领域代表不同的含义。在计算机领域,魔数有两个含义,一指用来判断文件类型的魔数;二指程序代码中的魔数,也称魔法值。当前这个魔数主要用于判断文件类型

    class文件的结构是怎么样的?
    这个问题暂时不深入研究,只是一笔带过。以后有可能会开一个新坑,我们目前只需要知道class文件构成有魔数、版本信息等。

    注意:验证阶段完毕,字节流才被允许进入Java虚拟机中

  • 元数据验证
    语义分析:
    1.这个类是否父类(Object除外)
    2.这个类是否继承了不被允许继承的父类(父类是final)

  • 字节码验证
    主要目的是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。

  • 符号引用验证
    将符合引用转化为直接引用

3.准备

给类的变量(static变量)分配内存空间,设置一个默认的初始值。
比如int为0,boolean为false,引用类型为null

  public class A{
    //static int a;//0
    //int a;//会报错
    static int a = 6666;//准备阶段,a的值还是为0
    static final int b = 8888; //常量在准备阶段就会被赋值为8888
    public static void main(String[] args){
        System.out.println(a);//0
    }
  }

4.解析

将符号引用转换为直接引用

符号引用:可以理解为一种标识
直接引用:可以理解直接执行内存中的地址

解析阶段的主要工作有:

  • 类及接口的解析
  • 类方法的解析
  • 接口方法的解析
  • 字段解析

5.初始化

  • 执行类的静态变量的赋值
  • 执行类的静态代码块
  public class A{
    //准备阶段,a的值还是为0
    //初始化阶段,a的值将真正被赋值为6666
    static int a = 6666;
  }

类初始化和对象初始化的差异

  public class A {
    //加载类的初始化阶段执行静态代码块
    static {
      System.out.println("A static");
    }
    public A(){
      System.out.println("A construct");
    }
  }

  class B extends  A{
    static {
      System.out.println("B static");
    }

    public B(){
      System.out.println("B construct");
    }

    public static void main(String[] args){
      //类加载完毕之后,基于Class对象去才会创建AB对象
      A a = new B();
      a = new B();
    }
  }

  //运行的结果
  A static
  B static
  A construct
  B construct
  A construct
  B construct

参考阅读

posted @ 2023-02-12 20:42  搬砖的杰先生  阅读(7)  评论(0)    收藏  举报