JVM 类的加载过程,以及什么是双亲委派模型?

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 63w+ 字,讲解图 2808+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2200+ 小伙伴加入学习 ,欢迎点击围观

Java 通过引入字节码和 JVM 机制,提供了强大的跨平台能力。那么 JVM 又是如何加载我们的 class 类的呢?

一般来说,我们把 Java 的类加载过程分为三个主要步骤:

  • 1.加载

  • 2.链接

  • 3.初始化

上述具体行为在 Java 虚拟机规范中已有明确定义,可参考链接:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html

首先是加载阶段(Loading),它是 Java 将字节码数据文件从不同的数据源读取到 JVM 中,并映射成 JVM 认可的数据结构(Class 对象),这里说的数据源可能是各种各样的形态,如 jar 文件,class 文件,也有可能是网络数据源等;如果输入的数据不是 ClassFile 的结构,则会抛出 ClassFormatError.

Note: 加载阶段是用户参与的阶段,我们可以自定义类加载器,去实现自己的类加载过程。

然后到第二阶段,链接阶段(Linking), 这是比较核心的步骤,简单说是把原始的类定义信息平滑的转入 JVM 运行的过程。而这一过程又可以细分为三步:

  • 1.验证(Verification), 这是虚拟机安全的重要保障,JVM 需要核验字节信息是否符合 Java 虚拟机规范,若不符合,则 VerifyError, 这样就防止了恶意信息或者不合规矩的信息危害 JVM 运行。

  • 2.准备(Preparation), 创建类或接口中的静态变量,并初始化静态变量的初始值。注意,这里的初始化有别于下面的显式初始化阶段,侧重点在于分配所需的内存空间,不会进一步去执行 JVM 指令。

  • 3.解析(Resolution), 这一步会将常量池中的符号引用替换为直接引用。

最后一步是初始化阶段(intialization), 这一步真正去执行类的初始化代码逻辑,包括静态字段赋值的动作,以及静态代码块内的逻辑,编译器在编译阶段就会把这部分的逻辑整理好,另外,父类的初始化逻辑优先于当前类。

再说说双亲委派模型,简单来说就是当前类加载器视图加载某个类型的时候,除非父类加载器找不到相应类型,否则尽量将这个任务交给父类加载器去完成。它的目的是为了避免重复加载 Java 类型。

相关文章