Java虚拟机的类加载机制全面解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
云解析DNS,个人版 1个月
简介: JVM把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被JVM直接使用的Java类型,这就是JVM的类加载机制。

什么是类加载机制

JVM把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被JVM直接使用的Java类型,这就是JVM的类加载机制。
如果你对Class文件的结构还不熟悉,可以参考之前的文章Class文件结构全面解析(上)Class文件结构全面解析(下)

类的生命周期

类从被加载到内存中,到被卸载出内存,一共分为以下几步:

  1. 加载(Loading)
  2. 验证(Verification)
  3. 准备(Preparation)
  4. 解析(Resolution)
  5. 初始化(Initialization)
  6. 使用(Using)
  7. 卸载(Unloading)

类加载的全过程,包括其中的加载验证准备解析初始化几个阶段。

加载

加载是类加载的第一阶段,在这一步中JVM规范要求完成了以下三件事:

  1. 通过一个类的全限定名来获取定义这个类的二进制字节流。
  2. 将这个字节流多代表的静态存储结构转化为方法区的运行时数据结构。
  3. 在内存中生成一个代表这个类的java.lang.Class对象。

以上要求其实并不具体,JVM的具体实现和应用都是比较灵活的。比如:获取这个类的二进制字节流,并没有说从哪获取,怎么获取,于是就有了从压缩包中读取(jar、war、ear)、从网络中获取(Applet)、运行时计算生成(动态代理)。对于不是数组的类的加载,我们可以定义自己的类加载器去控制字节流的获取方式。但是,对于数组类就不一样了,因为数组类本身不是通过类加载器创建的,而是JVM直接创建的。

验证

这一阶段是为了保证Class文件的字节流中包含的信息符合当前JVM的要求,并且不危害JVM自身的安全。大致分为以下四个阶段:

文件格式验证

验证字节流是否符合Class文件格式的规范,能不能被当前JVM处理。验证点比较多,比如:是否以魔数0xCAFEBABE开头、主次版本号是否在当前JVM的处理范围内、常量池的常量是否有不被支持的常量类型、CONSTANT_Utf8_info类型的常量中是否有不符合UTF8编码的数据等等。这个阶段是基于二进制字节流进行验证的,只有这个阶段验证通过了,字节流才能进入内存的方法区储存。

元数据验证

这个阶段主要是对类的元数据信息进行语义分析和校验,保证不存在不符合Java语言规范的元数据信息。比如:除了java.lang.Object以外的类是否有父类、是否继承了一个不允许被继承的类、非抽象类是否实现了其父类或接口中要求实现的所有方法、是否覆盖了父类的final字段等等。

字节码校验

这个阶段通过数据流和控制流分析,确保程序语义是合法的、符合逻辑的。比如:放置和使用操作栈时数据类型保证一致、保证跳转指令不会跳转到方法体以外的字节码指令上、保证方法体中的类型转换是有效的等等。

符号引用校验

这个阶段是对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验,它发生在解析步骤中,确保解析能正常执行,比如:符号引用中通过字符串描述的全限定名是否能找到对应的类、符号引用中的类字段方法的访问性是否可以访问当前类等等。

准备

在这个阶段里,为静态变量分配内存并设置静态变量初始值。这里说的初始值通常情况下,不是代码中写的初始值,而是数据类型的零值。代码中写的初始值,是在初始化阶段赋值的。如果是静态常量(被final修饰),这个阶段就会被直接赋值为代码中写的初始值。

解析

在这个阶段里,JVM把常量池内的符号引用替换为直接引用。符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可,它和JVM实现的内存布局无关。直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄,它是和JVM实现的内存布局相关的。如果有了直接引用,那么引用的目标肯定在内存中存在。

解析主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符的符号引用进行,分别对应常量池的CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info、CONSTANT_MethodType_info、CONSTANT_MethodHandle_info和CONSTANT_InvokeDynamic_info。

初始化

初始化阶段才真正开始执行类中定义的字节码,也是执行类构造器<clinit>()方法的过程。<clinit>()方法是由编译器自动收集类中的所有静态变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序是用语句在源文件中出现的顺序所决定的,静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,静态语句块可以赋值,但是不能访问。

JVM会保证在子类的<clinit>()方法执行之前,父类的<clinit>()方法已经执行完毕,也就是说父类中定义的静态语句块要优先于子类的变量赋值操作。如果类没有静态语句块,也没有对静态变量赋值,编译器就不会为这个类生成<clinit>()方法。接口的<clinit>()方法不需要先执行父接口的<clinit>()方法,只有当父接口中定义的变量使用时,父接口才会被初始化。

JVM会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步。如果一个线程在执行这个类的<clinit>()方法,其他线程都需要阻塞等待,当<clinit>()方法执行完后,其他线程也不会再次进入<clinit>()方法。同一个类加载器下,一个类只会被初始化一次。

结语

这次我们了解了类加载过程的几个阶段,分别是加载验证准备解析初始化加载是把二进制字节码载入内存,验证是校验字节流中包含的信息是否符合当要求,准备是为静态变量分配内存并设置静态变量初始值,解析是把常量池内的符号引用替换为直接引用,初始化是执行所有静态变量的赋值动作和静态语句块中的语句。

相关文章
|
11天前
|
缓存 Java 调度
Java并发编程:深入解析线程池与Future任务
【7月更文挑战第9天】线程池和Future任务是Java并发编程中非常重要的概念。线程池通过重用线程减少了线程创建和销毁的开销,提高了资源利用率。而Future接口则提供了检查异步任务状态和获取任务结果的能力,使得异步编程更加灵活和强大。掌握这些概念,将有助于我们编写出更高效、更可靠的并发程序。
|
11天前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
10天前
|
存储 算法 安全
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
20 0
|
12天前
|
设计模式 Java
Java中的设计模式及其应用场景解析
Java中的设计模式及其应用场景解析
|
3天前
|
存储 监控 算法
Java 内存管理与垃圾回收机制深度解析
本文深入探讨了Java的内存管理与垃圾回收(GC)机制,从JVM内存结构出发,详细分析了堆、栈、方法区的职能及交互。文章重点讨论了垃圾回收的核心概念、常见算法以及调优策略,旨在为Java开发者提供一套系统的内存管理和性能优化指南。 【7月更文挑战第17天】
|
3天前
|
Java 编译器 开发者
Java 内存模型深度解析
本文旨在深入探讨Java内存模型的复杂性及其对并发编程的影响。通过揭示内存模型的核心原理、JMM的结构,并结合具体案例和数据分析,本文将帮助读者理解Java内存模型如何确保多线程程序的正确性和性能,以及如何在实际应用中有效利用这一模型进行高效的并发编程。 【7月更文挑战第17天】
9 4
|
4天前
|
Java
Java中的异常处理机制深度解析
本文旨在深入探讨Java语言中异常处理的机制,从基础概念到高级应用,全面剖析try-catch-finally语句、自定义异常以及异常链追踪等核心内容。通过实例演示和代码分析,揭示异常处理在Java程序设计中的重要性和应用技巧,帮助读者构建更为健壮和易于维护的程序。
|
6天前
|
监控 Java API
Java并发编程之线程池深度解析
【7月更文挑战第14天】在Java并发编程领域,线程池是提升性能、管理资源的关键工具。本文将深入探讨线程池的核心概念、内部工作原理以及如何有效使用线程池来处理并发任务,旨在为读者提供一套完整的线程池使用和优化策略。
|
10天前
|
安全 Java 开发者
Java面试题:Java内存模型解析,Java内存模型的基本概念和它的重要性,Java内存模型中的“可见性”和“有序性”,以及具体实现?
Java面试题:Java内存模型解析,Java内存模型的基本概念和它的重要性,Java内存模型中的“可见性”和“有序性”,以及具体实现?
13 1
|
13天前
|
Java 程序员 测试技术
解析Java中的反射机制及其应用场景
解析Java中的反射机制及其应用场景

推荐镜像

更多