2026年7月11日 · 5 分钟阅读

JVM 入门:Java 虚拟机、类加载机制与双亲委派模型

梳理 JVM 基本概念、Java 技术体系、类加载时机、类加载过程、类加载器和双亲委派模型。

学习 JVM,不能只把它当成面试题。线程死锁、内存溢出、性能抖动、类冲突、线上排查,很多 Java 项目的重难点最终都会落到 JVM 这一层。

JVM 广义上是一套虚拟机规范,狭义上通常指 JDK 里的具体虚拟机实现。日常说的 JVM,大多指 HotSpot。

为什么要学习 JVM

JVM 解决的是 Java 程序如何运行的问题。

如果只会写业务代码,遇到下面这些问题时就很容易停在表面:

  • 为什么一个类明明存在,运行时却报 ClassNotFoundException
  • 为什么两个线程会死锁。
  • 为什么堆内存还有空间,应用却频繁 Full GC。
  • 为什么修改了 JVM 参数,却没有任何效果。
  • 为什么同样的代码在不同 JDK 版本下表现不一样。

JVM 知识不是为了让代码显得复杂,而是为了在问题出现时知道从哪里下手。

Java 技术体系

Java 技术体系不只是 Java 语言本身,通常包括四部分:

组成说明
Java 程序设计语言语法、类型系统、面向对象能力
Java 类库 APIJDK 提供的基础类库
第三方类库商业机构和开源社区提供的库
JVM执行字节码、管理内存、提供运行时环境

Kotlin、Groovy、Scala、Clojure 等语言也可以运行在 JVM 上,因为 JVM 真正执行的是字节码,而不只服务于 Java 源代码。

类什么时候会被加载

类加载不是 Java 文件写好后就立刻发生,而是在运行时按需进行。

常见触发时机有四类:

  1. 遇到 newgetstaticputstaticinvokestatic 等指令时,如果类还没有初始化,就会触发初始化。
  2. 使用反射调用类时,如果类还没有初始化,也会触发初始化。
  3. 初始化子类时,如果父类还没有初始化,会先初始化父类。
  4. JVM 启动时,会先初始化用户指定的主类,也就是包含 main 方法的类。

理解这些时机,对排查静态变量初始化顺序、类加载异常和反射行为很有帮助。

类加载过程

类加载完整生命周期可以概括为:

加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载

其中前五步最关键。

阶段主要工作
加载根据类的全限定名获取二进制字节流,并创建 Class 对象
验证确认字节码符合 JVM 规范,不会破坏虚拟机安全
准备为类变量分配内存,并设置默认初始值
解析将常量池中的符号引用转换为直接引用
初始化执行类构造器 <clinit>,为静态变量赋程序指定值

加载阶段主要做三件事:

  • 通过类的全限定名获取 class 文件的二进制字节流。
  • 把字节流里的静态数据结构转换为方法区的运行时数据结构。
  • 在堆中创建代表该类的 java.lang.Class 对象。

准备阶段和初始化阶段的区别

准备阶段容易和初始化阶段混淆。

比如:

public class User {
    public static int count = 10;
}

在准备阶段,count 会先被设置为默认值 0;到了初始化阶段,才会执行赋值逻辑,把它设置为 10

这也是为什么 JVM 类加载看起来抽象,但其实和代码执行顺序强相关。

类加载器有哪些

JVM 的类加载通过 ClassLoader 完成。常见类加载器包括:

类加载器负责范围
Bootstrap ClassLoader加载 JDK 核心类库
Extension ClassLoader加载扩展类库,JDK 9 后机制有所变化
Application ClassLoader加载应用 classpath 下的类
自定义 ClassLoader按业务需要加载指定路径、网络、加密 class 等

自定义类加载器通常继承 ClassLoader,重写类查找逻辑,用于插件化、热部署、隔离不同版本依赖等场景。

双亲委派模型

双亲委派模型的核心规则是:一个类加载器收到加载请求后,先把请求交给父加载器处理;父加载器无法加载时,子加载器才尝试自己加载。

流程大致是:

应用类加载器 -> 扩展类加载器 -> 启动类加载器

如果父加载器能加载,就由父加载器完成;如果父加载器加载不了,才向下回到子加载器。

双亲委派解决什么问题

双亲委派主要解决两个问题。

第一是安全。应用不能随便写一个 java.lang.String 替换 JDK 自带的核心类。

第二是类型一致性。同一个类如果被不同类加载器重复加载,JVM 会认为它们是不同类型。双亲委派可以尽量保证核心类由统一加载器加载。

什么时候会打破双亲委派

双亲委派不是绝对不能打破。常见场景包括:

  • SPI 机制需要父加载器加载的代码反过来调用子加载器中的实现类。
  • Web 容器需要隔离不同应用的依赖。
  • 插件系统需要独立加载、卸载插件。
  • 热部署需要重新加载某些 class。

打破双亲委派不是为了炫技,而是为了解决隔离、扩展和动态加载问题。

小结

JVM 入门可以先抓住一条线:

  1. JVM 是 Java 程序运行的基础环境。
  2. 类不是一次性全部加载,而是在运行时按需加载。
  3. 类加载过程包括加载、验证、准备、解析、初始化。
  4. 类加载器负责把 class 字节码加载进 JVM。
  5. 双亲委派模型保证核心类安全和类型一致性。

理解类加载之后,再看运行时数据区、对象创建和 GC,就会顺很多。