JVM虚拟机的类加载机制详解

 更新时间:2023年12月19日 09:47:11   作者:初念初恋  
这篇文章主要介绍了JVM虚拟机的类加载机制详解,类是在运行期间第一次使用时动态加载的,而不是一次性加载所有类,因为如果一次性加载,那么会占用很多的内存,需要的朋友可以参考下

一、类的生命周期

类是在运行期间第一次使用时动态加载的,而不是一次性加载所有类。因为如果一次性加载,那么会占用很多的内存。

11.png

包括以下 7 个阶段:

  • 加载(Loading)
  • 验证(Verification)
  • 准备(Preparation)
  • 解析(Resolution)
  • 初始化(Initialization)
  • 使用(Using)
  • 卸载(Unloading)

二、类的加载过程

包含了加载、验证、准备、解析和初始化这 5 个阶段。

加载

加载过程完成以下三件事:

  • 通过类的完全限定名称获取定义该类的二进制字节流。
  • 将该字节流表示的静态存储结构转换为方法区的运行时存储结构。
  • 在内存中生成一个代表该类的 Class 对象,作为方法区中该类各种数据的访问入口。

其中二进制字节流可以从以下方式中获取:

  • 从 ZIP 包读取,成为 JAR、EAR、WAR 格式的基础。
  • 从网络中获取,最典型的应用是 Applet。
  • 运行时计算生成,例如动态代理技术,在 java.lang.reflect.Proxy 使用 ProxyGenerator.generateProxyClass 的代理类的二进制字节流。
  • 由其他文件生成,例如由 JSP 文件生成对应的 Class 类。

验证

JVM 会在该阶段对二进制字节流进行校验,只有符合 JVM 字节码规范的才能被 JVM 正确执行。该阶段是保证 JVM 安全的重要屏障,下面是一些主要的检查。

  • 确保二进制字节流格式符合预期(比如说是否以 cafe bene 开头)。
  • 是否所有方法都遵守访问控制关键字的限定。
  • 方法调用的参数个数和类型是否正确。
  • 确保变量在使用之前被正确初始化了。
  • 检查变量是否被赋予恰当类型的值。

准备

JVM 会在该阶段对类变量(也称为静态变量,static 关键字修饰的)分配内存并初始化(对应数据类型的默认初始值,如 0、0L、null、false 等)。

此时不会分配实例变量的内存,因为实例变量是在实例化对象时一起创建在Java 堆中的。而且此时类变量是赋值为零值,即 int 类型的零值为 0,引用类型零值为 null,而不是代码中显示赋值的数值。

解析

该阶段将常量池中的符号引用转化为直接引用。

在 class 文件中常量池里面存放了字面量和符号引用,符号引用包括类和接口的全限定名以及字段和方法的名称与描述符。

在 JVM 动态链接的时候需要根据这些符号引用来转换为直接引用存放内存使用。

初始化

该阶段是类加载过程的最后一步。在准备阶段,类变量已经被赋过默认初始值,而在初始化阶段,类变量将被赋值为代码期望赋的值。换句话说,初始化阶段是执行类构造器方法的过程。

三、类加载时机

  • new、getstatic、putstatic、invokestatic 这 4 个字节码指令时对类进行初始化(即:实例化对象、读写静态对象、调用静态方法时,进行类的初始化);
  • 使用反射机制对类进行调用时,进行类的初始化;
  • 初始化一个类,其父类没有初始化时,先初始化其父类;
  • 虚拟机启动时,初始化一个执行主类;
  • 使用 JDK1.7 的动态语言支持时,如果 MethodHandle 实例的解析结果为 REF_getstatic、REF_putstatic、REF_invokestatic 的方法句柄(即:读写静态对象或者调用静态方法),则初始化该句柄对应类。

四、类加载器分类

讲到类加载不得不讲到类加载的顺序和类加载器。

Java 中大概有四种类加载器,分别是:启动类加载器(Bootstrap ClassLoader),扩展类加载器(Extension ClassLoader),系统类加载器(System ClassLoader),自定义类加载器(Custom ClassLoader),依次属于继承关系(注意这里的继承不是 Java 类里面的 extends)

classloader2.jpg

  • 启动类加载器(Bootstrap ClassLoader):主要负责加载存放在Java_Home/jre/lib下,或被-Xbootclasspath参数指定的路径下的,并且能被虚拟机识别的类库(如rt.jar,所有的java.*开头的类均被Bootstrap ClassLoader加载),启动类加载器是无法被Java程序直接引用的。
  • 扩展类加载器(Extension ClassLoader):主要负责加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载Java_Home/jre/lib/ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.*开头的类),开发者可以直接使用扩展类加载器。
  • 系统类加载器(System ClassLoader):主要负责加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
  • 自定义类加载器(Custom ClassLoader:自己开发的类加载器。

五、双亲委派原则

类加载器在加载 class 文件的时候,遵从双亲委派原则,意思是加载依次由父加载器先执行加载动作,只有当父加载器没有加载到 class 文件时才由子类加载器进行加载。这种机制很好的保证了 Java API 的安全性,使得 JDK 的代码不会被篡改。

六、Java字节码文件中的JVM指令

1、创建一个 Java 源文件 Test02.java,并在 main 方法中完成简单的逻辑操作,如下所示。

public class Test02 {
    public static void main(String[] args) {
        int i = 5;
        int j = 10;
        int k = i + j;
        System.out.println(k);
    }
}

2、在终端通过 javac 命令编译 HelloWorld.java。

javac Test02.java

3、反编译成我们能看懂的 JVM 指令,这里我们使用 javap -c 命令完成。

javap -c Test02.class

4、反编译之后的 JVM 指令如下所示。

    Compiled from "Test02.java"
    public class org.example.jvm.Test02 {
     public org.example.jvm.Test02();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
      public static void main(java.lang.String[]);
         Code:
           0: iconst_5
           1: istore_1
           2: bipush        10
           4: istore_2
           5: iload_1
           6: iload_2
           7: iadd
           8: istore_3
           9: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
          12: iload_3
          13: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
          16: return
    }

解释一下上述的 JVM 指令:

第 1 行表示当前的字节码文件编译自 Test02.java。

第 3 行表示调用 Test02的无参构造函数来实例化当前对象。

第 4 行到第 7 行表示无参构造函数的执行流程。

第 5 行表示把 this 压入操作数栈中。

第 6 行表示调用 Test02父类 Object 的无参构造,我们知道每个对象在实例化的时候都会默认先实例化其父类对象,并且默认调用父类的无参构造。

第 7 行 return 表示构造方法执行完毕。

第 10 行到第 22 行表示 main 方法的执行流程。

第 11 行表示将常量 5 压入操作数栈。

第 12 行表示取出操作数栈栈顶元素,即 5,然后保存到局部变量表第 1 个位置,即变量 i。

第 13 行表示将常量 10 压入操作数栈。

第 14 行表示取出操作数栈栈顶元素,即 10,然后保存到局部变量表第 2 个位置,即变量 j。

第 15 行表示将局部变量表第 1 个变量(i)压入操作数栈。

第 16 行表示将局部变量表第 2 个变量(j)压入操作数栈。

第 17 行表示取出操作数栈中的前两个值相加,并将结果压入操作数栈顶。

第 18 行表示取出操作数栈栈顶元素,保存到局部变量表第 3 个位置,即变量 k。

第 19 行表示读取静态实例 PrintStream。

第 20 行表示将局部变量表第 3 个变量(k)压入操作数栈。

第 21 行表示调用 PrintStream 的 println 方法,将操作数栈顶元素(变量 k)输出。

第 22 行 return 表示 main 方法执行完毕。

到此这篇关于JVM虚拟机的类加载机制详解的文章就介绍到这了,更多相关JVM类加载机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring中的@Cacheable缓存注解详解

    Spring中的@Cacheable缓存注解详解

    这篇文章主要介绍了Spring中的@Cacheable缓存注解详解,数据库查找的流程是先要从磁盘拿到数据,再刷新到内存,再返回数据。磁盘相比于内存来说,速度是很慢的,为了提升性能,就出现了基于内存的缓存,需要的朋友可以参考下
    2023-05-05
  • Java设计模式之策略模式

    Java设计模式之策略模式

    这篇文章介绍了Java设计模式之策略模式,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-10-10
  • Maven Pom 文件中的隐式依赖导致Jar冲突问题

    Maven Pom 文件中的隐式依赖导致Jar冲突问题

    这篇文章主要介绍了Maven Pom 文件中的隐式依赖导致Jar冲突问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • 从零开始学JAVA之可变参数

    从零开始学JAVA之可变参数

    本文是从零开始学JAVA的第一篇,属于Java基础知识介绍的第一部分,主要介绍Java的可变参数,非常使用,希望对大家有所帮助
    2014-10-10
  • Python连接Java Socket服务端的实现方法

    Python连接Java Socket服务端的实现方法

    这篇文章主要介绍了Python连接Java Socket服务端的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • 分享J2EE的13种核心技术

    分享J2EE的13种核心技术

    在本文中我将解释支撑J2EE的13种核心技术:JDBC, JNDI, EJBs, RMI, JSP, Java servlets, XML, JMS, Java IDL, JTS, JTA, JavaMail 和 JAF,对j2ee的13种核心技术感兴趣的朋友一起学习吧
    2015-11-11
  • 一文带你学会Java网络编程

    一文带你学会Java网络编程

    网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。这篇文章将带大家深入了解一下Java的网络编程,需要的可以了解一下
    2022-08-08
  • Java实现数组反转翻转的方法实例

    Java实现数组反转翻转的方法实例

    本篇文章主要介绍了Java实现数组反转翻转的方法实例,详细的介绍了3种实现方法,有兴趣的可以了解一下。
    2017-04-04
  • Java优秀类库Hutool使用示例

    Java优秀类库Hutool使用示例

    Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,涵盖了Java开发开发中的方方面面,使用Hutool可节省开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug
    2023-02-02
  • MyBatis-Plus拦截器实现数据权限控制的方法

    MyBatis-Plus拦截器实现数据权限控制的方法

    MyBatis-Plus是一款基于MyBatis的增强工具,它提供了一些便捷的功能和增强的查询能力,数据权限控制是在系统中对用户访问数据进行限制的一种机制,这篇文章主要给大家介绍了关于MyBatis-Plus拦截器实现数据权限控制的相关资料,需要的朋友可以参考下
    2024-01-01

最新评论