JVM 的生命周期是怎么样的

发布于:2025-03-08 ⋅ 阅读:(98) ⋅ 点赞:(0)

JVM 的生命周期是指 JVM 实例从启动到终止的整个过程。一个 Java 应用程序通常对应一个 JVM 实例(除非使用 JNI 等技术在同一进程中创建多个 JVM 实例,但这并不常见)。

JVM 的生命周期阶段:

  1. 启动 (Startup):

    • 创建 JVM 实例: 当你使用 java 命令运行 Java 程序时,操作系统会创建一个新的进程,并在该进程中启动一个 JVM 实例。
    • 加载和初始化:
      • 查找并加载 JDK: 找到 JRE (Java Runtime Environment) 的位置.
      • 创建引导类加载器 (Bootstrap Class Loader): 加载核心类库(rt.jar 等)。
      • 创建扩展类加载器 (Extension Class Loader) 和应用程序类加载器 (Application Class Loader): 分别加载扩展类库和应用程序的类。
      • 加载 main 方法所在的类: 使用应用程序类加载器加载包含 main 方法的类。
      • 初始化类: 执行类的静态初始化块和静态变量赋值。
    • 命令行参数: 解析传入java命令的参数.
  2. 运行 (Execution):

    • 执行 main 方法: JVM 调用 main 方法,开始执行 Java 程序。
    • 类加载: 在程序运行过程中,根据需要动态加载类。
    • 字节码执行: JVM 的执行引擎解释或编译执行字节码。
    • 内存管理: JVM 分配和管理内存,进行垃圾回收。
    • 线程管理: JVM 创建和管理线程。
    • 异常处理: JVM 处理程序中发生的异常。
  3. 终止 (Termination):

    • 正常终止:
      • 当程序执行完 main 方法,并且所有非守护线程(non-daemon threads)都已结束时,JVM 正常终止。
      • 可以通过调用 System.exit(status) 方法显式终止 JVM。status 是退出状态码(0 表示正常退出,非 0 表示异常退出)。
    • 异常终止:
      • 如果程序中发生了未捕获的异常,并且没有设置默认的未捕获异常处理器,JVM 会异常终止。
      • 可以通过 Thread.setDefaultUncaughtExceptionHandler() 设置默认的未捕获异常处理器。
    • 外部终止:
      • 用户可以通过操作系统命令(例如,在 Linux 中使用 kill 命令)强制终止 JVM 进程。
      • JVM 可能会收到操作系统发送的终止信号(例如,SIGTERM)。
    • 钩子 (Shutdown Hooks):
      • 在 JVM 终止之前,可以注册一些钩子函数(shutdown hooks),用于执行一些清理操作(例如,关闭数据库连接、释放资源等)。
      • 可以使用 Runtime.getRuntime().addShutdownHook(Thread hook) 方法注册钩子函数。
      • 钩子函数会在以下情况下执行:
        • 程序正常退出。
        • 调用 System.exit()
        • 用户中断程序(例如,按下 Ctrl+C)。
        • 系统关闭。
      • 钩子函数执行的顺序是不确定的。

总结流程图:

+----------------+
|    启动 JVM     |  (java 命令)
+----------------+
        |
        V
+----------------+
|  加载和初始化    |
|  - 查找并加载 JDK |
|  - 创建类加载器   |
|  - 加载 main 类   |
|  - 初始化类      |
+----------------+
        |
        V
+----------------+
|    运行程序     |
|  - 执行 main 方法|
|  - 类加载       |
|  - 字节码执行    |
|  - 内存管理     |
|  - 线程管理     |
|  - 异常处理     |
+----------------+
        |
        V
+----------------+
|    终止 JVM     |
|  - 正常终止      |
|  - 异常终止      |
|  - 外部终止      |
|  - 执行钩子函数   |
+----------------+

代码示例 (演示钩子函数):

public class JVMLifecycle {

    public static void main(String[] args) {

        // 注册钩子函数
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("JVM 即将终止,执行清理操作...");
            // 在这里执行清理操作 (例如,关闭数据库连接、释放资源等)
        }));

        System.out.println("程序开始执行...");

        // 模拟程序运行一段时间
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("程序执行完毕...");

        // 可以选择显式退出 (也可以不调用 exit,让程序自然结束)
        // System.exit(0);
    }
}

运行结果:

程序开始执行...
程序执行完毕...
JVM 即将终止,执行清理操作...

注意:

  • 如果程序中存在死循环或无限等待,JVM 可能永远不会终止。
  • 守护线程 (daemon thread) 不会阻止 JVM 终止。当所有非守护线程都结束后,JVM 会强制终止所有守护线程。
  • 钩子函数应该尽量简短,避免执行耗时的操作,否则可能会导致 JVM 无法正常终止。
  • 不要在钩子函数中调用 System.exit(),否则会导致死循环。

网站公告

今日签到

点亮在社区的每一天
去签到