Java Main方法都写过,JVM如何调用它的你知道吗?
首先我们写一段Java中非常经典的Hello World程序:
然后我们使用Java提供的工具进行编译和执行:
这个[java]命令是JDK提供的一个由c和c++编写的可执行程序,今天我们就来分析一下它是如何最终执行到我们上面编写的Java代码的。
总体路程图
下面这张图画出了java命令加载并执行我们java代码的过程:
看完整体流程图,接下来我就对其中关节点进行进一步的分析。
可执行程序[java]的main方法
[java]命令既然是一个c和c++的程序,那么它的入口函数肯定是main方法了,我们首先就来分析分析它的main方法。
在main方法中大体干了两件事:1、参数预处理;2、调用JLI_Launch方法。参数预处理主要是把环境变量_JAVA_OPTIONS指定的参数加入的参数列表中去(如果有的化)。
JRE版本选择
这个过程的方法名称叫做:SelectVersion,然而和版本选择关系并不是很大!这一步主要是从环境变量读取MainClass名称或者加载Jar包的manifest配置。
解析manifest过程:
需要注意的是,当配置了_JAVA_VERSION_SET的时候就不会去解析jar包的manifest文件了。
创建执行环境
这个过程是会分操作系统的,每一种操作系统实现过程略有不同,但是大体流程是一样的。如果命令行参数中指定了是32位还是64位,就会判断当前的操作系统是否支持,windows中的实现代码如下:
在这个过程中还会校验需要运行的jvm类型,一般我们都是使用默认的server类型,所以这里就不进行深入分析了。
加载JVM
当执行环境创建成功以后,就需要加载JVM了。这也是一个不同操作系统有不同实现代码的过程。主要是不同操作系统对于动态库的加载过程是有区别的。
动态库加载完以后,就从动态库中查找下面几个函数:
这几个方法在后续的JVM初始化的时候会使用到。
解析命令行参数
这个时候就会对所有的命令行参数进行解析,并根据解析的结果初始化一些数据。部分解析代码如下图:
调用JavaMain函数
JVMInit会新建一个线程,然后把JavaMain函数作为这个线程的回调函数。JavaMain函数最重要的事情就是创建VM(创建VM过程比较复杂,后续会单独介绍,这里就不展开了)和加载MainClass main方法,然后执行main方法。代码如下图所示: