(一)JVM运行机制——启动流程
2020-04-19 本文已影响0人
十六线程序员
最近重新学习了JVM,从源码角度来深入理解JVM,后续将分多个章节对JVM进行介绍。
这边主要介绍JVM的启动流程,并从源码的角度去加强理解。
注:因为部分源码过长,图片截取部分源码并不完整,具体可以去看jdk的源码
JVM启动流程
![](https://img.haomeiwen.com/i20915159/e48c86d1d68cde03.png)
1. 执行java命令启动虚拟机,虚拟机的启动入口位于java.c文件下的JavaMain()方法
![](https://img.haomeiwen.com/i20915159/d6388ec605da80ef.png)
![](https://img.haomeiwen.com/i20915159/71ff5791ffb8bfbb.png)
2. 装载配置。这一步的目的是了根据当前JRE环境的路径和系统版本寻找jvm.cfg文件,并从该文件中确定jvm的类型,具体实现如下:
(1)首先通过java_md.c文件下的GetJREPath()方法获取JRE环境的路径
![](https://img.haomeiwen.com/i20915159/8f38a1da43c83e1d.png)
(2)其次调用java_md.c文件下ReadKnownVMs()方法读取JRE路径\lib\ARCH(CPU构架)\jvm.cfg文件,其中ARCH是通过调用GetArchPath()方法获取的,在window下有三种情况:amd64、ia64和i386
![](https://img.haomeiwen.com/i20915159/948c4fc2b2a54049.png)
![](https://img.haomeiwen.com/i20915159/140b5e979f0e7122.png)
例如在这里,楼主本地的jvm.cfg位置如下图所示,CPU构架为amd64
![](https://img.haomeiwen.com/i20915159/d43919c6a1440847.png)
(3)在获取到jvm.cfg文件之后,通过调用CheckJvmType()方法确定JVM的类型,先判断是否通过-J、-XXaltjvm=或-J-XXaltjvm=参数指定,如果没有,则读取JVM.cfg文件中配置的第一个类型
![](https://img.haomeiwen.com/i20915159/dca3b63f77f23adb.png)
3. 根据配置寻找jvm.dll文件。根据上一步获取到的JVM类型,调用GetJVMPath()方法获取到jvm.dll文件的路径
![](https://img.haomeiwen.com/i20915159/9e196606bf206644.png)
4.初始化JVM。这一步包括装载jvm.dll动态连接库、初始化jvm.dll并挂接到JNIEnv(JNI调用接口)实例、调用JNIEnv实例装载并处理class类
(1)装载jvm.dll动态连接库。这一步是由java.c文件调用java_md.c中的LoadJavaVM()方法实现的。
![](https://img.haomeiwen.com/i20915159/8bfb9867b56a4985.png)
![](https://img.haomeiwen.com/i20915159/a9898574e3e4e680.png)
(2)初始化jvm.dll并挂接到JNIEnv(JNI调用接口)实例。通过java.c文件中的InitializeJVM()方法完成。
![](https://img.haomeiwen.com/i20915159/cd981e72ff58b10c.png)
在main函数中定义的JNIEnv就能够获取到该方法返回的实例,就可以对class文件进行处理了
![](https://img.haomeiwen.com/i20915159/fa6e0ebf1370243c.png)
(3)调用JNIEnv实例装载并处理class类。根据需要执行的文件类型,调用不同的方法进行类的加载。具体实现如下:
如果是执行class方法的话,main函数直接调用java.c中LoadMainClass()方法装载该类。
![](https://img.haomeiwen.com/i20915159/d71fd2fb1b234193.png)
其次,如果要执行的文件类型是jar的话,具体步骤如下图(楼主在java.c中并没有发现GetMainClassName函数,这里留个疑问,待我去深入理解)
![](https://img.haomeiwen.com/i20915159/3e10246e55d0e442.png)
5.找到main方法并运行
上一步中已经通过LoadMainClass()方法获取到该类,main函数中调用JNIEnv实例的GetStaticMethodID()方法查找装载的class主类中的main()方法,然后判断该方法是否为public,最后调用JNIEnv实例的CallStaticVoidMethod()方法调用该java类的main方法
![](https://img.haomeiwen.com/i20915159/6013839a8a1fc42e.png)
总结
以上就是 JVM启动流程及涉及到的方法,对于源码的解读后续我会继续总结和学习。