jvm.dll 加载过程
b、装载jvm.cfg虚拟机动态连接库配置文件是通过java.c中函数:ReadKnownVMs实现的。
该函数首先组合jvm.cfg文件的绝对路径,JRE路径+\lib+\ARCH(CPU构架)+\jvm.cfgARCH(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.703/01/23##Copyright2003SunMicrosystems,
- Inc.Allrightsreserved. #SUNPROPRIETARY/CONFIDENTIAL.Useissubjecttolicenseterms.
- #####ListofJVMsthatcanbeusedasanoptiontojava,javac,etc. #Orderisimportant--irstinthislististhedefaultJVM.
- #NOTEthatthisboththisfileanditsformatareUNSUPPORTEDand #WILLGOAWAYinafuturerelease.
- ##YoumayalsoselectaJVMinanarbitrarylocationwiththe #"-XXaltjvm="option,butthattooisunsupported
- #andmaynotbeavailableinafuturerelease. #-clientKNOWN-serverKNOWN-hotspotALIASED_TO-client-
- classicWARN-nativeERROR-greenERROR
(如果细心的话,我们会发现在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虚拟机名称,第二部分为配置参数,比如行:“-clientKNOWN”则“-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-clienttest”则ReadKnownVMs会读取参数“-client”然后查找jvm.cfg读入的参数中是否有jvm名称为“-client”的,如果有则去掉jvm名称前的“-”直接返回“client”;而如果在运行java程序时使用如下参数:“java-XXaltjvm=D:\java\j2sdk1.4.2_04\jre\bin\clienttest”,则ReadKnownVMs会直接返回“D:\java\j2sdk1.4.2_04\jre\bin\client”;如果不带上面参数执行如:“javatest”,因为在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-clienttest”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\clienttest”路径为:jvm类型字符串+\JVM.dll即为:“D:\java\j2sdk1.4.2_04\jre\bin\client”+“\JVM.dll”第三种情况“javatest”为:“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-clienttest.ScanDirectory----_JAVA_LAUNCHER_DEBUG----