源码角度来深入理解JVM
这边主要介绍JVM的启动流程,并从源码的角度去加强理解。
注:因为部分源码过长,图片截取部分源码并不完整,具体可以去看jdk的源码
JVM启动流程
1. 执行java命令启动虚拟机,虚拟机的启动入口位于java.c文件下的JavaMain()方法
2. 装载配置。这一步的目的是了根据当前JRE环境的路径和系统版本寻找jvm.cfg文件,并从该文件中确定jvm的类型,具体实现如下:
(1)首先通过java_md.c文件下的GetJREPath()方法获取JRE环境的路径
(2)其次调用java_md.c文件下ReadKnownVMs()方法读取JRE路径\lib\ARCH(CPU构架)\jvm.cfg文件,其中ARCH是通过调用GetArchPath()方法获取的,在window下有三种情况:amd64、ia64和i386
例如在这里,楼主本地的jvm.cfg位置如下图所示,CPU构架为amd64
(3)在获取到jvm.cfg文件之后,通过调用CheckJvmType()方法确定JVM的类型,先判断是否通过-J、-XXaltjvm=或-J-XXaltjvm=参数指定,如果没有,则读取JVM.cfg文件中配置的第一个类型
3. 根据配置寻找jvm.dll文件。根据上一步获取到的JVM类型,调用GetJVMPath()方法获取到jvm.dll文件的路径
4.初始化JVM。这一步包括装载jvm.dll动态连接库、初始化jvm.dll并挂接到JNIEnv(JNI调用接口)实例、调用JNIEnv实例装载并处理class类
(1)装载jvm.dll动态连接库。这一步是由java.c文件调用java_md.c中的LoadJavaVM()方法实现的。
(2)初始化jvm.dll并挂接到JNIEnv(JNI调用接口)实例。通过java.c文件中的InitializeJVM()方法完成。
在main函数中定义的JNIEnv就能够获取到该方法返回的实例,就可以对class文件进行处理了
(3)调用JNIEnv实例装载并处理class类。根据需要执行的文件类型,调用不同的方法进行类的加载。具体实现如下:
如果是执行class方法的话,main函数直接调用java.c中LoadMainClass()方法装载该类。
其次,如果要执行的文件类型是jar的话,具体步骤如下图(楼主在java.c中并没有发现GetMainClassName函数,这里留个疑问,待我去深入理解)
5.找到main方法并运行
上一步中已经通过LoadMainClass()方法获取到该类,main函数中调用JNIEnv实例的GetStaticMethodID()方法查找装载的class主类中的main()方法,然后判断该方法是否为public,最后调用JNIEnv实例的CallStaticVoidMethod()方法调用该java类的main方法
总结
以上就是 JVM启动流程及涉及到的方法