Java虚拟机

义项:Java程序运行环境
Java虚拟机

Java虚拟机(Java Virtual Machine,JVM)是一种能够执行Java字节码的虚拟计算机,通常以软件形式在真实操作系统上运行,为Java程序提供与硬件、操作系统无关的执行环境[1]。Java源代码先由编译器编译成字节码,再由虚拟机加载、校验并解释或编译为本地机器码执行,正是这一层抽象使同一份字节码可在多种平台上不加修改地运行[2]。虚拟机还负责内存分配与垃圾回收,是Java技术体系的核心组成部分[1]。

目录
  1. 定义
  2. 原理
  3. 发展历程
  4. 应用
  5. 局限
  6. 参见

定义

Java虚拟机是一个抽象的计算机,由一套指令集和运行时数据区构成,本身并不对应某台具体的物理机器[1]。它以栈式机器的结构实现,具备自己的字节码指令集、类文件格式和内存模型,程序只能在符合该规范的具体实现中运行[1]。技术规范只规定外部可观察的行为,并未限定垃圾回收算法、即时编译策略等内部实现方式,以给实现者留出优化空间[1]。在Java平台中,虚拟机位于操作系统与Java程序之间,与核心类库共同组成Java运行环境,而后者又与开发工具一起构成JDK[2]。

每一款虚拟机实现都必须能识别类文件格式,某些实现还可识别其他二进制格式[1]。由于规范面向的是字节码而非Java语言本身,其他能够编译为合规类文件的语言也可以在虚拟机上运行[3]。

原理

虚拟机的工作从类加载开始。类加载器按全限定名获取类的二进制字节流,将其中的静态存储结构转换为方法区的运行时结构,并在内存中生成对应的Class对象作为访问入口[4]。随后进入链接阶段,依次完成验证、准备与解析:验证检查类文件是否符合规范、是否存在安全风险,准备为静态变量分配内存并设默认值,解析把常量池中的符号引用换成直接引用[1]。最后执行初始化,为静态变量赋上程序指定的初值[4]。

运行时数据区主要由方法区、堆、虚拟机栈、程序计数器和本地方法栈组成。方法区与堆由虚拟机内所有线程共享,方法区存放类信息、常量和代码,堆用于分配程序创建的对象并由垃圾回收器管理[5]。每个线程拥有独立的栈和程序计数器,前者保存方法调用的帧,帧内包含局部变量表和操作数栈,后者记录当前执行指令的地址[5]。

字节码的执行通常兼用解释与编译两种方式。程序启动初期,解释器逐条翻译并执行字节码;虚拟机同时统计方法的调用与循环次数,把反复执行的部分识别为热点代码,交由即时编译器生成优化后的本地机器码,之后再执行时直接调用机器码[6]。这种混合模式在启动响应与长期运行性能之间取得平衡,规范支持的指令约200条,涵盖加载存储、算术运算、类型转换、控制转移、方法调用和基于监视器的并发控制等[5]。


flowchart LR

A[Java源代码 .java] --> B[javac编译]

B --> C[字节码 .class]

C --> D[类加载器: 加载/链接/初始化]

D --> E[运行时数据区: 方法区 堆 虚拟机栈]

E --> F[执行引擎]

F --> G[解释器]

F --> H[即时编译器]

F --> I[垃圾回收器]

G --> J[本地机器码执行]

H --> J

发展历程

虚拟机的概念出自Java语言早期的开发工作。1991年,Sun Microsystems启动面向消费电子设备的Green项目,需要一种平台无关的语言,虚拟机成为实现这一目标的机制[7]。1995年Java 1.0发布,虚拟机随之正式面世,此后逐步完善对类、对象、继承、多态等特性的支持,并在1998年的Java 1.2中改进了内存管理与垃圾回收[7]。

1997年,Sun收购Longview Technologies,获得其虚拟机技术;该产品于1999年4月以Java HotSpot Performance Engine的名义公开,并在此后成为Sun JDK的默认虚拟机[8][9]。它采用解释器与即时编译器协作的方式,通过执行计数找出热点方法再编译为本地代码,还支持以方法为单位的栈上替换编译[10]。

2006年,Sun在JavaOne大会上宣布开源Java,随后以GPL协议陆续公开包括HotSpot在内的JDK源码,并在此基础上建立OpenJDK项目[10]。规范本身也交由Java社区流程维护,自Java SE 5.0起由JSR 924负责,2006年又通过JSR 202支持修改类文件格式[1]。2010年Oracle收购Sun,HotSpot转由Oracle维护[9]。除HotSpot外,历史上还有BEA的JRockit、IBM的J9等实现,OpenJ9则由Eclipse基金会托管,可作为HotSpot的替代方案用于部分OpenJDK发行版[8][11]。

应用

虚拟机最主要的用途是运行编译后的Java程序。启动器读取主类的全限定名或带清单的JAR包,启动运行时环境、加载指定类并调用其main方法;运行时按引导类路径、扩展目录和用户类路径三处顺序搜索所需的类[12]。Java 9起引入模块化,开发者可用jlink从JDK中裁剪出只含所需模块的自定义运行时,随应用一起部署[13]。

在服务器与容器环境中,主流框架依赖虚拟机提供的稳定字节码语义实现依赖注入、切面织入和非阻塞I/O等功能;云原生部署时,类加载、即时编译预热与容器资源限制之间的配合会影响参数与基础镜像的选择[14]。游戏《我的世界》Java版即把定制运行时嵌入客户端分发,在线服务中也大量以容器方式部署虚拟机实例[13]。

移动平台上,Android设备运行的是基于寄存器的Android Runtime,并非严格的Java虚拟机,但类文件转换、字节码校验和受Java内存模型影响的设计思路与之相近[14]。

局限

虚拟机本身并不跨平台。字节码可以通用,但每类宿主操作系统都需要各自的虚拟机与运行时实现,虚拟机实现要调用本地系统资源才能完成工作[1]。规范对此不作统一规定,因此不同实现的语义相同而行为细节可能存在差别[1]。

启动开销与预热期是传统运行方式的固有代价。虚拟机启动时需加载大量类并初始化各子系统,耗时可达数秒乃至数十秒;应用还要经过一段时间的即时编译才能达到峰值性能,内存中也要为编译器和元数据保留空间[15]。在需要瞬时扩容的云原生与无服务器场景中,这一点构成明显制约[15]。

以提前编译为思路的方案可缓解上述问题,但代价同样存在。GraalVM的原生镜像在构建时进行封闭世界分析,只保留可达的类与方法,从而把启动时间压缩到毫秒级、显著降低内存占用,代价是构建耗时更长、产物体积更大,且反射、动态代理、序列化等动态特性需在构建期显式登记[15]。这类镜像也无法回到即时编译模式,运行时不再具备基于运行剖面的持续优化能力[16]。

此外,规范把垃圾回收算法、即时编译、去优化等留给实现决定,不同虚拟机在停顿时间、吞吐量和初始化行为上差异较大,跨实现迁移时需要重新评估性能表现[14]。

参见

  • Java —— 主要以Java虚拟机为目标平台的高级编程语言。

  • 字节码 —— 虚拟机执行的目标代码形式,介于源代码与机器码之间。

  • HotSpot —— 使用最广的Java虚拟机实现之一,采用解释与即时编译混合的执行方式。

  • 垃圾回收 —— 虚拟机自动管理堆内存的机制。

  • OpenJDK —— 以开源方式提供虚拟机与类库实现的Java平台项目。

  • GraalVM —— 提供提前编译原生镜像能力的运行时,用于缩短启动时间。

参考资料

  1. Java虚拟机 [引用日期2026-10-29]
  2. Java基础知识点 [引用日期2026-10-29]
  3. toc [引用日期2026-10-29]
  4. zongjie [引用日期2026-10-29]
  5. hxedu.com.cn 上的 PDF 文件 [引用日期2026-10-29]
  6. 基于 Java 技术的软件执行概述 [引用日期2026-10-29]
  7. Java 虚拟机的发展历程是怎样的? [引用日期2026-10-29]
  8. Java虚拟机--Java发展史Java虚拟机 [引用日期2026-10-29]
  9. HotSpot [引用日期2026-10-29]
  10. Java虚拟机家族考 [引用日期2026-10-29]
  11. view-source [引用日期2026-10-29]
  12. 工具和命令 [引用日期2026-10-29]
  13. 使用 jlink 的 Java 运行时 [引用日期2026-10-29]
  14. cleverence.com 上的网页 [引用日期2026-10-29]
  15. Java在云原生时代的挑战:GraalVM、Project Loom与未来的可能性 [引用日期2026-10-29]
  16. FaaS and Dynamic AOT [引用日期2026-10-29]
词条评价
词条统计

浏览次数:0 次

阅读量:0 次 · 阅读完成量:0 次

最近更新:2026-10-28T18:21:09Z

历史版本

本条目引用的词条
操作系统 Java运行环境 JDK Sun Microsystems Java社区流程 Eclipse基金会 Android Java 字节码 HotSpot 垃圾回收 OpenJDK GraalVM