当前位置: 首页 > news >正文

OpenJDK8源码系列01-JVM生命周期源码概览

1. 引言

JVM(Java 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.CreateJavaVM=0;ifn.GetDefaultJavaVMInitArgs=0;...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_CreateJavaVM,ifn->GetDefaultJavaVMInitArgs指向JNI_GetDefaultJavaVMInitArgs,ifn->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){...rslt=ContinueInNewThread0(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);}...mainClass=LoadMainClass(env,mode,what);..mainID=(*env)->GetStaticMethodID(env,mainClass,"main","([Ljava/lang/String;)V");...mainArgs=CreateApplicationArgs(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生命周期源码概览结束。

http://www.jsqmd.com/news/906939/

相关文章:

  • 用Wireshark抓包,一步步拆解IPv6 SLAAC自动配置的完整流程(附报文详解)
  • MATLAB一键运行Kriging代理模型工具包:含DACE核心库、4种建模脚本与3组均匀采样数据
  • 实测GPR数据不够用?手把手教你用Python给雷达图像加噪声(附去直达波代码)
  • 中小企业如何用Veo做出媲美4A水准的广告?—— 1套零外包流程、2个自研提效插件、3天极速交付(限免资源包已备好)
  • 告别虚拟机!在Win11上用WSL2装Kali Linux桌面,5分钟搞定渗透测试环境
  • 别再手动封装SRAM了!用Memory Wrapper工具一键搞定接口、ECC和时序调整
  • 米游社自动签到:3分钟搞定stoken配置的完整指南
  • 独立开发者如何利用Taotoken模型广场快速为产品选择合适的大模型
  • 2026年第二季度,如何选择评价高的洗发水直销工厂?深度剖析上海暄缘棠健康管理有限公司 - 2026年企业资讯
  • Gitee Team:关键领域项目管理的“系统闭环”实践与效能解析
  • 工业EtherCAT主站在RT-Linux上的DC同步实现与WKC错误优化
  • 从串口通信到文件传输:CRC-16 XMODEM校验在单片机项目中的实战应用指南
  • 别再让CUDA多线程打架了!手把手教你用atomicCAS实现一个简单的自旋锁
  • RHEL8系统管理员必看:用ELRepo源安全升级内核到kernel-ml,保姆级避坑指南
  • 2026 年 5 月基金从业备考指南:免费题库与软件实测对比 - 讲清楚了
  • YRC1000机器人与PLC通过标准以太网(UDP/TCP)实现稳定数据交换的工程调试包
  • 别再死记硬背SMO公式了!用Python手写一个SVM分类器,从原理到代码实战(含完整数据集)
  • 避坑指南:Hook PC微信收消息时,为什么你的call地址总不对?聊聊基址与版本差异
  • WPF项目直接可用的可缩放日历+日期时间选择器封装组件
  • Bambu Studio国际化开发实战:从零到一打造多语言3D打印软件
  • Windows Server上从零部署RuoYi-Vue:保姆级避坑指南(含Redis、Nginx配置)
  • 2026 年 5 月基金从业备考避坑:免费题库与电子版软件实测 - 讲清楚了
  • Unity崩了转UE5?一个独立开发者的真实踩坑与避坑全记录
  • 3大核心机制深度解析:BetterNCM-Installer的Rust GUI架构设计与Windows系统集成
  • playwright工具(四)codex的浏览器插件
  • git教程使用的一些心得
  • 上海软件开发服务商那么多,企业数字化转型期该如何精准选择
  • 土地利用模拟避坑指南:为什么你的IDRISI CA-Markov模型精度总是不达标?
  • day6:数组
  • Layuimini企业级后台架构最佳实践:高可用可扩展前端解决方案