1. 引言JVMJava Virtual Machine是 Java 程序的运行基石。理解 JVM 的生命周期即从启动到销毁的完整过程是深入掌握 Java 运行时机制的第一步。本文将从 OpenJDK8 源码出发概述在linux系统JVM 的启动、初始化、执行与销毁四个核心阶段的调用链帮助读者建立对 JVM 整体架构的宏观认知。2. JVM 启动入口JVM 的启动入口位于src/share/bin/main.c文件中的main()函数。// src/share/bin/main.cintmain(intargc,char**argv){...returnJLI_Launch(margc,margv,sizeof(const_jargs)/sizeof(char*),const_jargs,sizeof(const_appclasspath)/sizeof(char*),const_appclasspath,FULL_VERSION,DOT_VERSION,(const_progname!NULL)?const_progname:*margv,(const_launcher!NULL)?const_launcher:*margv,(const_jargs!NULL)?JNI_TRUE:JNI_FALSE,const_cpwildcard,const_javaw,const_ergo_class);}进入main函数JVM进程开始运行。该函数相对简单调用了JLI_Launch函数// src/share/bin/java.c/* * Entry point. */intJLI_Launch(intargc,char**argv,/* main argc, argc */intjargc,constchar**jargv,/* java args */intappclassc,constchar**appclassv,/* app classpath */constchar*fullversion,/* full version defined */constchar*dotversion,/* dot version defined */constchar*pname,/* program name */constchar*lname,/* launcher name */jboolean javaargs,/* JAVA_ARGS */jboolean cpwildcard,/* classpath wildcard*/jboolean javaw,/* windows-only javaw */jint ergo/* ergonomics class policy */){...CreateExecutionEnvironment(argc,argv,jrepath,sizeof(jrepath),jvmpath,sizeof(jvmpath),jvmcfg,sizeof(jvmcfg));ifn.CreateJavaVM0;ifn.GetDefaultJavaVMInitArgs0;...if(!LoadJavaVM(jvmpath,ifn)){return(6);}...returnJVMInit(ifn,threadStackSize,argc,argv,mode,what,ret);}JLI_Launch函数需要重点关注的是调用了CreateExecutionEnvironment、LoadJavaVM和JVMInit等函数。CreateExecutionEnvironment函数创建运行环境LoadJavaVM函数主要是加载JVM共享链接库libvjm.so,将函数指针ifn-CreateJavaVM指向JNI_CreateJavaVMifn-GetDefaultJavaVMInitArgs指向JNI_GetDefaultJavaVMInitArgsifn-GetCreatedJavaVMs指向JNI_GetCreatedJavaVMs。// src/solaris/bin/java_md_solinux.cintJVMInit(InvocationFunctions*ifn,jlong threadStackSize,intargc,char**argv,intmode,char*what,intret){...returnContinueInNewThread(ifn,threadStackSize,argc,argv,mode,what,ret);}JVMInit调用了ContinueInNewThread函数去开启新线程。// src/share/bin/java.cintContinueInNewThread(InvocationFunctions*ifn,jlong threadStackSize,intargc,char**argv,intmode,char*what,intret){...rsltContinueInNewThread0(JavaMain,threadStackSize,(void*)args);return(ret!0)?ret:rslt;}}ContinueInNewThread函数调用了ContinueInNewThread0函数去开启新线程。如果成功创建新线程由新线程调用JavaMain函数。到目前为止在linux内核角度来看linux内核已经为该JVM进程创建了两个TASK_STRUCT.。一个是之前main函数所在的TASK_STRUCT暂且叫它A一个是新线程所在的TASK_STRUCT暂且叫它B。A关联的线程会一直等待B关联的线程运行完再继续运行。如果创建新线程失败则由原有的线程调用JavaMain函数。到目前为止在linux内核角度来看linux内核已经为该JVM进程创建了一个TASK_STRUCT.// src/share/bin/java.cintJNICALLJavaMain(void*_args){...if(!InitializeJVM(vm,env,ifn)){JLI_ReportErrorMessage(JVM_ERROR1);exit(1);}...mainClassLoadMainClass(env,mode,what);..mainID(*env)-GetStaticMethodID(env,mainClass,main,([Ljava/lang/String;)V);...mainArgsCreateApplicationArgs(env,argv,argc);...(*env)-CallStaticVoidMethod(env,mainClass,mainID,mainArgs);..LEAVE();}JavaMain函数中调用了InitializeJVM、LoadMainClass、(*env)-GetStaticMethodID、CreateApplicationArgs、 (*env)-CallStaticVoidMethod等关键函数和宏LEAVE().InitializeJVM函数极为重要做了很多事情初始化ClassLoader,创建了堆并进行初始化创建垃圾收集器和相应的垃圾收集策略后面在详解InitializeJVM再详细展开。LoadMainClass函数找到并加载JAVA应用的Main Class.(*env)-GetStaticMethodID获取JAVA应用Main Class的main方法ID。CreateApplicationArgs函数创建JAVA应用Main Class main方法的参数。(*env)-CallStaticVoidMethod函数开始调用Java应用Main Class的main方法这里开始运行JAVA程序代码。宏LEAVE()在JAVA应用程序执行完后对JVM进行销毁。至此JVM生命周期源码概览结束。