jvm执行java helloworld分为四个阶段:1.启动器解析命令并加载jvm动态库;2.jni创建jvm实例并初始化运行时子系统;3.引导类加载器加载核心类库并准备运行时环境;4.应用类加载器加载主类并调用main方法。

当你在终端输入 java HelloWorld,JVM 并不是直接跳进 main 方法——它先要“搭好舞台”,再请演员登台。整个过程可清晰划分为四个紧密衔接的阶段:启动器执行、JVM 实例创建与初始化、核心类库加载与运行时数据区准备、主类加载与 main 调用。
1. 启动器(java.exe)解析命令并加载 JVM 动态库
操作系统首先启动 java.exe(Windows)或 java(Linux/macOS),该程序本质是一个原生可执行文件,不运行 Java 字节码,只负责桥接系统与 JVM:
- 按顺序查找 JRE 路径:先检查自身所在目录的
jre/子目录;若无,则查注册表(Windows)或环境变量JAVA_HOME;最终定位到$JAVA_HOME/lib/server/libjvm.so(Linux)或%JAVA_HOME%\bin\server\jvm.dll(Windows) - 解析全部命令行参数:区分标准选项(如
-version)、-X非标准选项(如-Xms256m)、-XX高级选项(如-XX:+UseG1GC)和系统属性(-Dkey=value),并校验合法性 - 根据
jvm.cfg确定目标 JVM 类型(如-server或-client),加载对应动态库,并为后续调用准备参数结构体JavaVMInitArgs
2. JVM 实例创建与运行时子系统初始化
启动器调用 JNI 接口 JNI_CreateJavaVM(),正式进入 JVM 内部初始化流程:
- 分配初始内存空间:按物理内存比例计算默认堆大小(
-Xms≈ 总内存 / 64,下限 8MB;-Xmx≈ 总内存 / 4,上限通常 1GB),同时设置线程栈大小(如 Linux x64 默认 1MB) - 初始化关键子系统:启动垃圾回收器(根据参数选择 G1、ZGC 等)、预热 JIT 编译器、配置日志系统(如
-Xlog:gc)、启用诊断接口(如-XX:+UnlockDiagnosticVMOptions) - 构建运行时数据区雏形:为方法区(Metaspace)、堆、虚拟机栈、本地方法栈、程序计数器预留地址空间,但此时尚未填充内容
3. 引导类加载器加载核心类库并准备运行时环境
JVM 启动后立即激活 Bootstrap ClassLoader(引导类加载器),它是用 C++ 实现的、最顶层的类加载器:
- 从
$JAVA_HOME/jre/lib/rt.jar(Java 8 及以前)或模块化镜像(Java 9+)中加载java.lang.Object、java.lang.String、java.lang.Class、java.lang.System等核心类 - 完成这些类的加载 → 验证 → 准备(为静态字段赋默认值,如
int counter = 0)→ 解析(符号引用转直接引用)→ 初始化(执行<clinit></clinit>,包括静态块和静态变量显式赋值) - 创建并初始化主线程(
main所在线程),同时初始化System、SecurityManager、标准输入输出流等基础运行时服务
4. 应用类加载器定位主类并执行 main 方法
启动器将控制权交还给 JVM 后,最后一步聚焦于用户代码:
- 根据命令行指定的类名(如
HelloWorld)或-jar中 MANIFEST.MF 的Main-Class,由 Application ClassLoader(系统类加载器)加载该类字节码 - 对该类执行完整的类加载五阶段:加载(读取 .class 文件)、验证(确保字节码安全)、准备(为
static final String GREETING分配内存并设默认值)、解析(绑定方法符号)、初始化(执行静态初始化块,打印"静态初始化块执行: counter = 0") - 通过 JNI 查找
main方法签名public static void main(String[]),构造字符串数组参数,然后调用CallStaticVoidMethod,真正进入 Java 用户代码逻辑
至此,从敲下回车键到第一行 System.out.println 输出,JVM 已完成从操作系统进程到完整 Java 运行时环境的构建。每一步都不可跳过,且环环相扣——参数错一个,可能卡在启动器校验;类路径不对,会停在类加载失败;内存不足,则在堆初始化阶段抛出 OutOfMemoryError。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











