JVM 不是“运行 Java 的黑盒”。它加载 Class 文件,为线程和对象管理内存,解释或编译字节码,并通过垃圾收集器回收 不可达对象。读完本文,你能把一次方法调用放回这条完整链路,而不是孤立地背诵堆、栈和 GC 名词。
Table of contents
Open Table of contents
从源码到执行结果
一段 Java 代码经历四个主要阶段:
javac把.java源码编译成平台无关的.class文件。- 类加载器找到字节并创建 JVM 中的类。
- JVM 校验、准备、解析并按需初始化类。
- 执行引擎解释字节码,或把热点方法即时编译成当前 CPU 的机器码。
运行实验室中的字节码样例下载:
mvn package
java -cp target/classes dev.elaine.jvmlab.BytecodeSample
程序输出 5050。Class 文件没有绑定 macOS 或 Linux 的机器指令;目标机器上的 JVM 决定如何执行它。
四个协作部分
| 部分 | 主要责任 | 常见证据 |
|---|---|---|
| 类加载子系统 | 找到、校验和初始化类 | -Xlog:class+load=info |
| 运行时数据区 | 保存对象、栈帧、类元数据等 | Heap Dump、线程转储、NMT |
| 执行引擎 | 解释字节码并即时编译热点 | JFR、-XX:+PrintCompilation |
| 垃圾收集器 | 判断对象可达性并回收空间 | -Xlog:gc*、JFR GC 事件 |
JVM(Java Virtual Machine)规范规定 Class 文件、指令集和运行时行为;HotSpot 是一个具体实现。对象头大小、JIT 策略和收集器细节多属于实现,不应误写成所有 JVM 都必须遵守的规范。
线程执行方法时发生什么
每个线程拥有自己的 JVM 栈。调用方法时,JVM 创建栈帧(Frame),其中包含局部变量表、操作数栈和动态链接信息。 对象通常位于线程共享的堆中,栈帧只保存基本值或对象引用。
方法里的 new 触发对象分配,但对象不一定永远进入堆。JIT 可能通过逃逸分析消除分配或把字段拆开计算。诊断时应观察
实际分配事件,不要仅凭源码中的 new 推算内存占用。
先观察当前 JVM
运行以下只读命令查看 JVM、堆与系统识别结果:
java --version
java -XshowSettings:vm -version
java -XshowSettings:system -version
-XshowSettings:system 能帮助你确认容器的 CPU 和内存限制是否被识别。具体输出随 JDK、操作系统和容器环境变化,
启动日志应成为部署证据的一部分。
JVM 规范的运行时数据区章节定义了规范边界。 后续文章会逐层验证 HotSpot 的具体行为。
下一步
阅读类加载的双亲委派、隔离与打破方式,理解同名类为什么可能 属于不同类型。