快捷搜索:

java源代码分析----jvm.dll装载过程

简述

众所周知java.exe是java class文件的履行法度榜样,但实际上java.exe法度榜样只是

一个履行的外壳,它会装载jvm.dll(windows下,以下皆以windows平台为例,

linux下和solaris下着实类似,为:libjvm.so),这个动态连接库才是java

虚拟机的实际操作处置惩罚所在。本文商量java.exe法度榜样是若何查找和装载jvm.dll

动态库,并调用它进行class文件履行处置惩罚的。

源代码

本文阐发之代码,《JavaTM 2 SDK, Standard Edition, v1.4.2 fcs

Community Source Release》,可从sun官方网站下载,主要阐发的源代码为:

j2se\src\share\bin\java.c

j2se\src\windows\bin\java_md.c

java.c是什么器械

‘java法度榜样’源代码

所谓‘java法度榜样’,包括jdk中的java.exe\javac.exe\javadoc.exe,java.c源

代码中经由过程JAVA_ARGS宏来节制天生的代码,假如该宏没定义则编译文件节制生

成java.exe否则编译文件节制天生其他的‘java法度榜样’。

比如:

j2se\make\java\javac\Makefile(这是javac编译文件)中:

$(CD) ../../sun/javac ; $(MAKE) $@ RELEASE=$(RELEASE) FULL_VERSION=$(FULL_VERSION)

j2se\make\sun\javac\javac\Makefile(由上面Makefile文件调用)中:

JAVA_ARGS = "{ \"-J-ms8m\", \"com.sun.tools.javac.Main\" }"

则由同一份java.c代码天生的javac.exe法度榜样就会直接调用java类措施:

com.sun.tools.javac.Main,这样使其履行起来就像是直接运行的一个exe文件,

而不决义JAVA_ARGS的java.exe法度榜样则会调用通报过来参数中的类措施。

从java.c的main进口函数提及

main()函数中前面一段为从新分配参数指针的处置惩罚。

然后调用函数:CreateExecutionEnvironment,该函数主要查找java运行情况的

目录,和jvm.dll这个虚拟机核心动态连接库文件路径所在。根据操作系统不合,

该函数有不合实现版本,但大年夜体处置惩罚逻辑相同,我们看看windows平台该函数的处

理(j2se\src\windows\bin\java_md.c)。

CreateExecutionEnvironment函数主要分为三步处置惩罚:

a、查找jre路径。

b、装载jvm.cfg中指定的虚拟灵便态连接库(jvm.dll)参数。

c、取jvm.dll文件路径。

实现:

a、查找jre路径是经由过程java_md.c中函数:GetJREPath实现的。

该函数首先调用GetApplicationHome函数,GetApplicationHome函数调用windows

API函数GetModuleFileName取java.exe法度榜样的绝对路径,以我的jdk安装路径为例,

为:“D:\java\j2sdk1.4.2_04\bin\java.exe”,然后去掉落文件名取绝对路径为:

“D:\java\j2sdk1.4.2_04\bin”,之后会在去掉落着末一级目录,现在绝对路径为:

“D:\java\j2sdk1.4.2_04”。

然后GetJREPath函数继承判断刚刚取的路径+\bin\java.dll组合成的这个java.dll

文件是否存在,假如存在则“D:\java\j2sdk1.4.2_04”为JRE路径,否则判断取得

的“D:\java\j2sdk1.4.2_04”路径+\jre\bin\java.dll文件是否存在,存在则

“D:\java\j2sdk1.4.2_04\jre”为JRE路径。假如上面两种环境都不存在,则从注

册表中去查找(拜见函数GetPublicJREHome)。

函数:GetPublicJREHome先查找

HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment\CurrentVersion

键值“当前JRE版本号”,判断“当前JRE版本号”是否为1.4做为版本号,假如是则

取HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment\“当前JRE版本号”

\JavaHome的路径所在为JRE路径。

我的JDK返回的JRE路径为:“D:\java\j2sdk1.4.2_04\jre”。

b、装载jvm.cfg虚拟灵便态连接库设置设置设备摆设摆设文件是经由过程java.c中函数:ReadKnownVMs实现

的。

该函数首先组合jvm.cfg文件的绝对路径,JRE路径+\lib+\ARCH(CPU构架)+\jvm.cfg

ARCH(CPU构架)的判断是经由过程java_md.c中GetArch函数判断的,该函数中windows平

台只有两种环境:WIN64的‘ia64’,其他环境都为‘i386’。我的为i386以是jvm.cfg

文件绝对路径为:“D:\java\j2sdk1.4.2_04\jre\lib\i386\jvm.cfg”。文件内容如

下:

## @(#)jvm.cfg  1.7 03/01/23# # Copyright 2003 Sun Microsystems, Inc. All rights reserved.# SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.# # ### List of JVMs that can be used as an option to java, javac, etc.# Order is important -- first in this list is the default JVM.# NOTE that this both this file and its format are UNSUPPORTED and# WILL GO AWAY in a future release.## You may also select a JVM in an arbitrary location with the# "-XXaltjvm=" option, but that too is unsupported# and may not be available in a future release.#-client KNOWN-server KNOWN-hotspot ALIASED_TO -client-classic WARN-native ERROR-green ERROR

(假如细心的话,我们会发明在JDK目录中我的为:“D:\java\j2sdk1.4.2_04\jre\bin\client”和“D:\java\j2sdk1.4.2_04\jre\bin\server”两个目录下都存在jvm.dll文件。而java恰是经由过程jvm.cfg设置设置设备摆设摆设文件来治理这些不合版本的jvm.dll的。)

ReadKnownVMs函数会将该文件中的设置设置设备摆设摆设内容读入到一个JVM设置设置设备摆设摆设布局的全局变量中,该函数首先跳过注释(以‘#’开始的行),然后读取以‘-’开始的行指定的jvm参数,每一行径一个jvm信息,第一部分为jvm虚拟机名称,第二部分为设置设置设备摆设摆设参数,比如行:

“-client KNOWN”则“-client”为虚拟机名称,而“KNOWN”为设置设置设备摆设摆设类型参数,“KNOWN”

表示该虚拟机的jvm.dll存在,而“ALIASED_TO”表示为另一个jvm.dll的又名,“WARN”

表示该虚拟机的jvm.dll不存在但运行时会用其他存在的jvm.dll替代履行,而“ERROR”

同样表示该类虚拟机的jvm.dll不存在且运行时不会找存在的jvm.dll替代而直接抛出差错

信息。

在运行java法度榜样时指定应用那个虚拟机的判断是由java.c中函数:CheckJvmType判断,该函数会反省java运行参数中是否有指定jvm的参数,然后从ReadKnownVMs函数读取的jvm.cfg数据布局中去查找,从而指定不合的jvm类型(终极导致装载不合jvm.dll)。有两种措施可以指定jvm类型,一种按照jvm.cfg文件中的jvm名称指定,第二种措施是直接指定,它们履行的措施分手是“java -J”、“java -XXaltjvm=”或“java -J-XXaltjvm=”。假如是第一种参数通报要领,CheckJvmType函数会取参数‘-J’后面的jvm名称,然后从已知的jvm设置设置设备摆设摆设参数中查找假如找到同名的则去掉落该jvm名称前的‘-’直接返回该值;而第二种措施,会直接返回“-XXaltjvm=”或“-J-XXaltjvm=”后面的jvm类型名称;假如在运行java时未指定上面两种措施中的任逐一种参数,CheckJvmType会取设置设置设备摆设摆设文件中第一个设置设置设备摆设摆设中的jvm名称,去掉落名称前面的‘-’返回该值。CheckJvmType函数的这个返回值会鄙人面的函数中汇同jre路径组合成jvm.dll的绝对路径。

比如:假如在运行java法度榜样时应用“java -J-client test”则ReadKnownVMs会读取参数“-client”然后查找jvm.cfg读入的参数中是否有jvm名称为“-client”的,假如有则去掉落jvm名称前的“-”直接返回“client”;而假如在运行java法度榜样时应用如下参数:

“java -XXaltjvm=D:\java\j2sdk1.4.2_04\jre\bin\client test”,则ReadKnownVMs

会直接返回“D:\java\j2sdk1.4.2_04\jre\bin\client”;假如不带上面参数履行如:

“java test”,由于在jvm.cfg设置设置设备摆设摆设文件中第一个存在的jvm为“-client”,以是函数

ReadKnownVMs也会去掉落jvm名称前的“-”返回“client”。着实这三中环境都是应用的

“D:\java\j2sdk1.4.2_04\jre\bin\client\jvm.dll”这个jvm动态连接库处置惩罚test这个class的,见下面GetJVMPath函数。

c、取jvm.dll文件路径是经由过程java_md.c中函数:GetJVMPath实现的。

由上面两步我们已经得到了JRE路径和jvm的类型字符串。GetJVMPath函数判断CheckJvmType

返回的jvm类型字符串中是否包孕了‘\’或‘/’假如包孕则以该jvm类型字符串+\jvm.dll作为JVM的全路径,否则以JRE路径+\bin+\jvm类型字符串+\jvm.dll作为JVM的全路径。

看看上面的例子,第一种环境“java -J-client test”jvm.dll路径为:

JRE路径+\bin+\jvm类型字符串+\jvm.dll 按照我的JDK路径则为:

“D:\java\j2sdk1.4.2_04\jre”+“\bin”+“\client”+“\jvm.dll”。

第二种环境“java -XXaltjvm=D:\java\j2sdk1.4.2_04\jre\bin\client test”路径为:

jvm类型字符串+\jvm.dll即为:“D:\java\j2sdk1.4.2_04\jre\bin\client”+“\jvm.dll”

第三种环境“java test”为:“D:\java\j2sdk1.4.2_04\jre”+“\bin”+“\client”

+“\jvm.dll”与环境一相同。以是这三种环境都是调用的jvm动态连接库“D:\javaj2sdk1.4.2_04\jre\bin\client\jvm.dll”处置惩罚test类的。

我们来进一步验证一下:

打开cmd节制台:

设置java装载调试

E:\work\java_research>set _JAVA_LAUNCHER_DEBUG=1

环境一

E:\work\java_research>java -J-client test.ScanDirectory

----_JAVA_LAUNCHER_DEBUG----

您可能还会对下面的文章感兴趣: