Hotspot启动和初始化源码解析

更新时间:2023-07-12 12:19:21 阅读: 评论:0

Hotspot启动和初始化源码解析
⽬录热门电视剧排行榜
学习⼀个复杂项⽬源码的最关键的⼀步是找准应⽤启动和对外提供服务的⼊⼝,从这些⼊⼝处开始顺藤摸⽠式的查看代码,可以对项⽬的各功能模块有⼀个整体宏观上的认识,并以此为切⼊点,有的放⽮,按需深⼊了解各功能模块的实现细节,这是最⾼效的学习源码的⽅式。JVM的启动⼊⼝在哪了?可以借助GDB的start命令查看。
1、JVM启动⼊⼝
OpenJDK的源码下载和编译可以参考,编译完成可以写⼀个HelloWorld.java作为测试代码,如下:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
反假货币
}
将其保存在编译后⽣成/build/linux-x86_64-normal-rver-slowdebug/jdk/bin/⽬录下,执⾏./javac HelloWorld.java将其编译成class⽂件,执⾏./java HelloWorld,程序正确打印则编译成功。执⾏gdb -q ./java进⼊gdb调试,执⾏t args HelloWorld设置启动参数,即执⾏./java的参数,执⾏start命令,gdb停在启动⼊⼝处,如下图:
启动⼊⼝在/home/openjdk/openjdk-jdk8u-master/jdk/src/share/bin/main.c:97,查看代码可知其核⼼启动⽅法是JLI_Launch。
2、JLI_Launch
其主要流程如下:
1. SelectVersion,从jar包中manifest⽂件或者命令⾏读取⽤户使⽤的JDK版本,判断当前版本是否合适
2. CreateExecutionEnvironment,设置执⾏环境参数
3. LoadJavaVM,加载libjvm动态链接库,从中获取JNI_CreateJavaVM,JNI_GetDefaultJavaVMInitArgs和
JNI_GetCreatedJavaVMs三个函数的实现,其中JNI_CreateJavaVM是JVM初始化的核⼼⼊⼝,具体实现在hotspot⽬录中
4. ParArguments 解析命令⾏参数,如-version,-help等参数在该⽅法中解析的
5. SetJavaCommandLineProp 解析形如-and=的命令⾏参数los系统
6. SetJavaLauncherPlatformProps 解析形如-Dsun.java.launcher.*的命令⾏参数
7. JVMInit,通过JVMInit->ContinueInNewThread->ContinueInNewThread0->pthread_create创建了⼀个新的线程,执⾏
JavaMain函数,主线程pthread_join该线程,在JavaMain函数中完成虚拟机的初始化和启动。
市政管网
执⾏export _JAVA_LAUNCHER_DEBUG=1设置环境变量,然后可以查看整个启动过程的⽇志,如下图:
枕秃是缺钙吗如点击LoadJavaVM时,eclip弹框如下:
该函数的实现到底是哪个⽂件了?为啥没有Linux的实现了?Linux和solaris都是类Unix系统,所以这⾥应该是共⽤solaris的实现,怎么证明了?⽤eclip 全局搜索包含java_md_solinux.c⽂件名的⽂件,其中位于jdk⽬录下的只有⼀个⽂件,k,如下
图:
如果不是macosx和windows则执⾏BUILD_LIBJLI_FILES += java_md_solinux.c ergo.c,即将  java_md_solinux.c这个⽂件加⼊到编译路径中,从⽽使⽤java_md_solinux.c的实现。除通过这种构建脚本的⽅式实现各操作系统兼容外,JVM还使⽤了宏定义和预处理的⽅式,如java_md.h中有⼀段代码,如下:
当定义了宏MACOSX以后,就包含java_md_macosx.h,否则包含java_md_solinux.h,这两个头⽂件包含了特定于该操作系统的特殊头⽂件和变量定义。类似这种代码在hotspot⽬录下特别常见,JVM通常将公共的代码放在share⽬录下,特定于操作系统的代码放在该操作系统的⽬录下,然后通过上述两种⽅式在编译打包时根据构建脚本配置或者宏定义编译打包成特定于操作系统的JDK,如下图:后天八卦图
这类宏是执⾏配置检查的configure根据所在的操作系统的特点在编译时⾃动注⼊进去,但是eclip没有执⾏configure这个过程,需要给编译器添加宏定义,从⽽让预处理器能够正确的包含头⽂件。添加⽅法是,在C++的⼯程上点击右键,选择properties,然后如下图操作点击Add:
孕妇能吃燕麦片吗
接着如下图,添加宏定义:
点击OK,然后Apply and Clo后编译器⾃动重新执⾏代码的预处理,引⼊正确的头⽂件。
4、JavaMain
JLI_Launch作为启动器,创建了⼀个新线程执⾏JavaMain函数,JLI_Launch所在的线程称为启动线程,执⾏JavaMain函数的称之为Main线程。JavaMain函数的主要流程如下:
1. InitializeJVM 初始化JVM,给JavaVM和JNIEnv对象正确赋值,通过调⽤InvocationFunctions结构体下的CreateJavaVM⽅法指
针实现,该指针在LoadJavaVM⽅法中指向libjvm动态链接库中JNI_CreateJavaVM函数。
2. LoadMainClass 获取应⽤程序的MainClass,即包含java程序启动⼊⼝main⽅法的类,
3. GetApplicationClass  JavaFX没有MainClass⽽是通过ApplicationClass启动的,这⾥获取ApplicationClass
4. PostJVMInit  将ApplicationClass作为应⽤名传给JavaFX本⾝,⽐如作为主菜单
5. (*env)->GetStaticMethodID  获取main⽅法的⽅法ID
6. CreateApplicationArgs  解析main⽅法的参数
7. (*env)->CallStaticVoidMethod  执⾏main⽅法
8. LEAVE main⽅法执⾏完毕,JVM退出,包含两步,(*vm)->DetachCurrentThread,让当前Main线程同启动线程断联,然后创建
⼀个新的名为DestroyJavaVM的线程,让该线程等待所有的⾮后台进程退出,并在最后执⾏(*vm)->DestroyJavaVM⽅法。
夏日古诗5、JavaVM和JNIEnv对象
点击JavaVM,eclip弹框如下:
在4个⽂件中都有定义,同⼀个⽂件中有两处定义,以jdk下⾯的⽬录为例,如下图:
__cplusplus宏表⽰当前系统⽀持C++,通常服务器操作系统如CentOS都⽀持C++,只有嵌⼊式这类微型操作系统不⽀持C++,纯C开发,我们只关注C++下的JavaVM实现即可,进⼀步查看两者的具体定义可知,JavaVM_只是对JNIInvokeInterface_下的⽅法指针做了⼀个包装,将其转换成类⽅法⽽已,如下:
⽽JNIInvokeInterface_结构体就只有⽅法指针,rerved0等保留的⽅法,如下:
进⼀步查看位于hotspot⽬录下的JavaVM的定义发现同jdk⽬录下的定义完全⼀样,初步判断jdk中JavaVM定义相当于接⼝,具体的实现在hotspot⽬录下,两者是隔离的src⽬录所以有两份定义的头⽂件。
JNIEnv对象同JavaVM对象,两者都是在同⼀个头⽂件jni.h中定义,定义⽅式⼀样,JNIEnv定义的⽅法更多,如下图:

本文发布于:2023-07-12 12:19:21,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1092536.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:定义   编译   线程   启动   实现   作为
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图