03_JVM(Java Virtual Machine)的生命周期

JVM 的生命周期对应一个独立运行的 Java 程序(进程级别),是 JVM 实例从启动→运行→终止的完整过程。

一、启动阶段:JVM 实例的初始化(创建→就绪)

当你执行java 类名命令时,操作系统会创建新进程并初始化 JVM 实例,核心是加载 JVM 运行所需的核心组件和程序入口类。

步骤 核心操作 通俗解释 & 关键说明
1. 创建 JVM 实例 操作系统调用java.exe(Windows)/java(Linux),分配进程内存,初始化类装载子系统、执行引擎、运行时数据区 JVM 先 "搭好架子",为后续执行程序做准备
2. 加载核心类库 引导类加载器(C++ 实现)加载$JAVA_HOME/jre/lib/rt.jar等核心类(如ObjectString 这是 JVM 的 "基础工具包",必须最先加载
3. 创建类加载器链 依次创建扩展类加载器(加载jre/lib/ext)、应用类加载器(加载 classpath 下的用户类) 形成「引导→扩展→应用」的类加载器层级,为后续加载用户类做准备
4. 加载并初始化 main 类 应用类加载器加载包含main方法的类,执行静态代码块、静态变量赋值(父类优先初始化) main类是程序入口,初始化完成后才具备执行条件
5. 解析命令行参数 解析-Xmx512m(堆内存)、-Dkey=value(系统属性)等参数,应用到 JVM 配置 定制 JVM 运行环境,比如调整内存大小

核心特点

  • 引导类加载器不继承java.lang.ClassLoader,是类加载的 "根";
  • 初始化顺序:父类静态代码 / 变量 → 子类静态代码 / 变量。

二、运行阶段:程序执行与资源管理(核心阶段)

启动完成后,JVM 进入最长的运行阶段,核心是执行main方法并管理内存、线程、异常等资源。

1. 核心执行逻辑

  • 执行入口:调用main方法(非守护线程),触发程序逻辑执行;

  • 类加载规则:运行时动态加载未加载的类,遵循双亲委派模型(子类加载器先委托父类加载,父类加载失败才自己加载);

  • 字节码执行方式:

    • 解释执行:逐行解释字节码(启动快、效率低);
    • JIT 编译:对热点代码(频繁执行的方法 / 循环)编译为机器码(启动慢、执行快)。

2. 核心资源管理

(1)内存管理(运行时数据区)

JVM 通过以下区域管理内存,也是 GC(垃圾回收)的核心操作对象:

区域 作用 核心特点
堆(Heap) 存储对象实例(如new Object() GC 主要区域,分为新生代(Eden/Survivor)、老年代
方法区(元空间) 存储类元数据、静态变量、字符串常量池 JDK8 + 用元空间(本地内存)替代永久代,避免永久代溢出
Java 栈 线程私有,存储方法栈帧(局部变量、操作数栈) 每个方法调用对应一个栈帧,方法结束则栈帧出栈
本地方法栈 native方法(如System.out.println())提供栈空间 支撑 Java 调用 C/C++ 实现的底层方法
程序计数器 线程私有,存储当前执行的字节码行号 唯一不会抛出OutOfMemoryError的区域
(2)垃圾回收(GC)
  • 触发条件:新生代满(Minor GC)、老年代满(Full GC)、手动调用System.gc()(不推荐);
  • 常用回收器:Serial(单线程)、Parallel(吞吐量优先)、G1(分区、低停顿)、ZGC(亚毫秒级停顿)。
(3)线程管理
  • 非守护线程(如main线程):JVM 必须等所有非守护线程结束才会终止;
  • 守护线程(如 GC 线程):由 JVM 管理,不阻止 JVM 终止;
  • 线程状态:新建→就绪→运行→阻塞→终止。
(4)异常处理

通过try-catch-finallythrowthrows处理异常,未捕获的异常会终止当前线程,但不影响其他线程。

三、终止阶段:JVM 实例的退出(清理→结束)

当满足终止条件时,JVM 会执行清理操作并退出进程,终止方式分为以下 4 类:

终止方式 触发条件 执行流程 注意事项
正常终止 所有非守护线程执行完毕 JVM 自动清理资源(释放内存、关闭文件句柄)→ 退出进程 最理想的终止方式
显式终止 调用System.exit(int status)/Runtime.getRuntime().exit() 先执行关闭钩子 → 终止所有线程 → 释放资源 → 退出 status=0表示正常退出,非 0 为异常退出
异常终止 未捕获的严重异常(如OutOfMemoryError 终止异常线程 → 若所有非守护线程结束,则 JVM 退出 可能导致资源未释放
外部终止 操作系统命令(kill -9 PID/taskkill /F /PID 直接终止进程,不执行任何清理操作 可能引发资源泄漏(如未关闭的数据库连接)

关键机制:关闭钩子(Shutdown Hook)

关闭钩子是 JVM 终止前执行的清理逻辑(如关闭数据库连接、记录日志),仅在正常 / 显式终止时执行(外部终止不执行)。

代码示例:注册关闭钩子
java 复制代码
package com.dwl.ex01_类加载子系统;

/**
 * @ClassName JVMShutdownHookDemo
 * @Description JVM关闭钩子(ShutdownHook)演示示例
 *              关闭钩子是JVM在退出前自动执行的线程,用于优雅地清理资源(如关闭数据库连接、释放文件句柄、保存程序状态等)
 * @Version 1.0.0
 * @Date 2026/1/18
 * @Author By Dwl
 */
public class JVMShutdownHookDemo {

    /**
     * 程序入口方法
     * @param args 命令行参数(本示例未使用)
     */
    public static void main(String[] args) {
        // 1. 注册JVM关闭钩子
        // Runtime.getRuntime():获取当前应用程序的运行时环境对象,用于与JVM交互
        // addShutdownHook(Thread hook):向JVM注册一个关闭钩子线程
        // 钩子线程会在JVM即将退出时被启动执行(JVM不保证多个钩子的执行顺序)
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            // 钩子线程的核心逻辑:执行资源清理操作
            System.out.println("===== 执行关闭钩子:开始清理资源 =====");

            // 实际业务场景中,可在这里执行以下操作:
            // 1. 关闭数据库连接池(如JDBC Connection、Redis连接等)
            // closeDBConnection();
            // 2. 释放打开的文件句柄、网络套接字
            // releaseFileHandles();
            // 3. 保存程序运行状态(如内存中的临时数据写入文件)
            // saveProgramState();
            // 4. 记录程序退出日志
            // logExitInfo();

            System.out.println("===== 关闭钩子执行完成:资源清理完毕 =====");
        }, "Custom-Shutdown-Hook-Thread")); // 给钩子线程命名,便于排查问题

        // 2. 模拟程序正常运行逻辑
        System.out.println("程序正常运行中...(等待5秒,可按Ctrl+C或等待自动退出触发钩子)");

        // 模拟程序执行耗时操作(睡眠5秒)
        try {
            // 线程睡眠5秒,模拟业务逻辑执行
            Thread.sleep(5000);
            System.out.println("程序正常执行完毕,即将触发JVM退出...");
        } catch (InterruptedException e) {
            // 捕获线程中断异常(如其他线程中断当前主线程)
            System.out.println("主线程睡眠被中断:" + e.getMessage());
            e.printStackTrace();
        }

        // 3. 显式终止JVM(可选)
        // System.exit(0):主动退出JVM,会触发关闭钩子执行
        // 注:如果注释掉这行,程序执行完main方法后正常退出,也会触发钩子;按Ctrl+C中断程序同样会触发
        // System.exit(0);
    }

    // ---------------------- 以下为示例业务方法(注释掉仅作演示) ----------------------
    /**
     * 示例:关闭数据库连接
     */
    // private static void closeDBConnection() {
    //     System.out.println("关闭数据库连接池...");
    //     // 实际代码:关闭Connection、释放连接池资源等
    // }

    /**
     * 示例:保存程序运行状态
     */
    // private static void saveProgramState() {
    //     System.out.println("保存程序临时状态到文件...");
    //     // 实际代码:将内存中的数据写入本地文件/数据库
    // }
}
关闭钩子注意事项
  1. 逻辑要简短,避免耗时操作(否则可能导致 JVM 无法正常终止);
  2. 不要调用System.exit()(会引发死循环);
  3. 多个钩子的执行顺序不确定。

四、JVM 生命周期流程图

正常终止(非守护线程结束)
显式终止(System.exit)
异常终止(未捕获异常)
外部终止(kill -9)
执行java命令
启动阶段:创建JVM实例→加载核心类库→初始化main类
运行阶段:执行main方法→动态加载类→内存/线程/异常管理
终止条件?
执行关闭钩子→清理资源→JVM退出
终止异常线程→若所有非守护线程结束→JVM退出
直接终止进程→无清理操作

五、核心特性与实际应用建议

1. 核心特性

  • 进程隔离:每个 Java 程序对应一个独立的 JVM 实例,实例间相互隔离;
  • 不可逆性:JVM 实例终止后,无法重启,需重新执行java命令创建新实例;
  • 守护线程不阻终止:仅非守护线程会决定 JVM 的生命周期。

2. 实际应用建议

  • 避免内存泄漏:及时移除静态集合中的无用对象,防止对象被长期持有;
  • 优化 GC 性能:根据业务场景调整堆大小(-Xms/-Xmx)、选择合适的 GC(如高并发场景用 G1/ZGC);
  • 合理使用关闭钩子:仅执行必要的清理操作,避免复杂逻辑;
  • 处理未捕获异常:通过Thread.setDefaultUncaughtExceptionHandler()设置全局异常处理器,避免程序崩溃。

总结

  1. JVM 生命周期分为启动(初始化核心组件)、运行(执行程序 + 管理资源)、终止(清理 + 退出)三个核心阶段;
  2. 双亲委派模型、GC、关闭钩子是各阶段的核心机制,直接影响程序稳定性和性能;
  3. 外部终止(如kill -9)会跳过清理流程,实际开发中应优先通过正常 / 显式方式终止 JVM

JVM(Java Virtual Machine)的生命周期 核心考点记忆口诀

启创环境加载类,运行执码管线程;满足条件即消亡,资源释放无残留。

  • 逐句拆解:

    1. 启创环境加载类:JVM 启动时先初始化内存分区、类加载子系统等核心环境,再加载入口类(如含 main 方法的类)和核心类库(rt.jar);
    2. 运行执码管线程:运行阶段核心是执行字节码指令,同时管理用户线程 / 守护线程(线程状态是退出的关键),还包含类的链接 / 初始化、GC 等操作;
    3. 满足条件即消亡:触发退出条件(如下文)时,JVM 进入终止流程;
    4. 资源释放无残留:JVM 销毁时会彻底释放内存、CPU 等系统资源,无残留占用。

JVM 消亡的核心触发条件:

  • 所有非守护线程执行完毕(最常见);
  • 主动调用System.exit(int)方法;
  • 虚拟机被外部终止(如 kill 命令、任务管理器结束);
  • 严重异常 / 错误导致虚拟机崩溃(如 OOM 未处理)。
相关推荐
沐雪架构师3 小时前
LangChain 1.0 Agent开发实战指南
开发语言·javascript·langchain
tod1133 小时前
力扣高频 SQL 50 题阶段总结(四)
开发语言·数据库·sql·算法·leetcode
2501_940007893 小时前
Flutter for OpenHarmony三国杀攻略App实战 - 战绩记录功能实现
开发语言·javascript·flutter
naruto_lnq3 小时前
C++中的桥接模式
开发语言·c++·算法
无限进步_3 小时前
面试题 02.02. 返回倒数第 k 个节点 - 题解与详细分析
c语言·开发语言·数据结构·git·链表·github·visual studio
夕除3 小时前
js--7
java
布谷歌3 小时前
面试题整理
java·开发语言
2301_790300964 小时前
数据分析与科学计算
jvm·数据库·python
爬山算法4 小时前
Hibernate(74)如何在CQRS架构中使用Hibernate?
java·架构·hibernate