Skip to content

Java 上层技术与 JVM 的关系

看似分层,实则一体

很多人把 Java 当作一门单纯的编程语言,但这个理解是片面的。Java 实际上是一个技术生态,而 JVM 正是这个生态的最底层支撑。

┌─────────────────────────────────────┐
│         应用层                       │
│  Spring / MyBatis / Kafka / ...    │
├─────────────────────────────────────┤
│         API 层                      │
│  java.lang / java.util / java.io   │
├─────────────────────────────────────┤
│         JVM 运行时                   │
│  类加载器 / 执行引擎 / 内存管理 / GC  │
├─────────────────────────────────────┤
│         操作系统层                   │
│     Linux / Windows / macOS         │
└─────────────────────────────────────┘

当你在 Spring Boot 中写一个 @Service 注解,当 MyBatis 执行一条 SQL,当 Kafka 推送一条消息——这些操作最终都会落地到 JVM 的某个内存区域里。框架层越厚,越需要对底层有清晰认知。

JVM 在整个 Java 技术栈中的角色

JVM 承担了三个关键职责:

1. 运行环境:让 Java 代码跑起来

没有 JVM,.class 文件就是一堆无意义的字节。JVM 负责加载字节码、解释或编译执行、管理内存——它是 Java 程序的「操作系统」。

java
// 你写的代码
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, JVM");
    }
}

编译后生成的 Hello.class,本质上是一条条 JVM 指令。JVM 读取这些指令,像一个虚拟 CPU 一样逐条执行,最终输出结果。这个过程不需要你知道指令是什么,但理解它能帮你排查问题。

2. 内存管理者:分配和回收

Java 区别于 C/C++ 的核心之一,就是不需要手动管理内存。对象创建时 JVM 分配内存,对象不再使用时 JVM 自动回收。这个「自动」背后是一套复杂的机制:

  • 对象的内存从哪来?(堆分配、TLAB)
  • 什么时候回收?(MinorGC、FullGC)
  • 怎么回收效率高?(标记-清除、复制、标记-压缩)

线上服务最常遇到的两类问题——内存溢出(OOM)GC 停顿——都与 JVM 的内存管理直接相关。不懂 JVM,排查这些问题就是盲人摸象。

3. 跨平台桥梁:Write Once, Run Anywhere

这是 Java 最响亮的口号,背后功臣正是 JVM。

不同的操作系统有不同的 CPU 指令集。Windows 的机器码和 Linux 的机器码不一样。如果让程序员自己处理这些差异,Java 绝不会流行起来。

JVM 的做法是:定义一套统一的字节码指令集,然后各平台提供各自的 JVM 实现。.class 文件是通用的,由具体平台的 JVM 负责翻译成本地指令执行。

Java 源文件 (.java)

        ▼  javac 编译
字节码文件 (.class)

        ▼  JVM 执行
Windows JVM ──→ Windows 本地指令
Linux JVM   ──→ Linux 本地指令
macOS JVM   ──→ macOS 本地指令

常见上层技术与 JVM 的对应关系

上层技术依赖 JVM 的哪些部分
Spring Boot类加载器(加载大量 Bean)、堆内存(对象分配)、GC
MyBatis代理对象(堆)、SQL 缓存(方法区/元空间)
Netty堆外内存(直接内存)、零拷贝(操作系统交互)
Kafka / RocketMQ顺序读写(堆 + 堆外)、GC 调优(高吞吐场景)
Hadoop / Spark大内存管理(-Xmx 设置)、GC 策略选择
Tomcat类加载器(多 Webapp 隔离)、线程栈(每个请求一个线程)

为什么框架开发者必须懂 JVM

使用框架和理解框架是两件事。以 Spring 为例:

  1. @Component 注解的 Bean 是怎么被扫描、创建、存入容器的?——涉及类加载器堆内存分配
  2. Spring 默认单例 Bean,多个线程访问同一个 Bean 会不会有问题?——涉及线程私有区(虚拟机栈)
  3. Bean 的循环依赖是怎么被检测和解决的?——涉及 JVM 对象创建过程
  4. 线上 OOM 了,dump 出来的堆里大量 Spring 相关的对象,怎么分析?——涉及堆内存结构MAT/Arthas等工具

越往深处走,越发现 JVM 是绕不开的一环。

本节小结

JVM 不是 Java 的一部分,它是 Java 生态的地基。上层技术不管多复杂,最终都要在 JVM 的规则下运行:

  • 类加载器决定你能用哪些类
  • 内存区域决定对象放哪里
  • 执行引擎决定代码跑多快
  • GC 决定内存能不能及时释放

理解 JVM,不是为了炫技,而是为了在问题来临时,能够从根源上找到答案。

下一节,我们聊聊 学习 JVM 的价值与面向人群

基于 VitePress 构建