OpenJDK源码分析(1)

对于Java程序来说,JVM是一台完整的机器,可是对于真正的机器或OS来说,JVM只是其中一个进程而已。作为一个进程,它又是如何启动的呢?如下来一步一步分析。(注,本文分析的JDK源代码是openjdk6,下载地址:http://download.java.net/openjdk/jdk6/)

JVM的进程入口是在...\jdk\src\share\bin\java.c。199行。该方法一开始初始化了一系列的指针并判断是否打开debug(通过set _JAVA_LAUNCHER_DEBUG=1打开).接下来就进入了CreateExecutionEnvironment函数,该函数主要作用是查找Java程序的运行目录。那么这个函数在中间到底做了些什么呢? 两件事:

(1)、查找jre路径:这个功能是通过...\jdk\src\
\bin\java_md.c中的GetJREPath函数实现的。首先其通过GetApplicationHome获取到路径,代码如下:

[code="c"]/*
* If app is "c:\foo\bin\javac", then put "c:\foo" into buf.
*/
jboolean
GetApplicationHome(char *buf, jint bufsize)
{
char *cp;
GetModuleFileName(0, buf, bufsize);
*strrchr(buf, '\\') = '\0'; /* remove .exe file name */
if ((cp = strrchr(buf, '\\')) == 0) {
/* This happens if the application is in a drive root, and
* there is no bin directory. */
buf[0] = '\0';
return JNI_FALSE;
}
*cp = '\0'; /* remove the bin\ part */
retur JNI_TRUE;
}[/code]


找到ApplicationHome之后,GetJREPath函数会通过如下的方式来确定JREPath。
[img]http://dl.iteye.com/upload/attachment/0062/3648/05d289ba-78c5-37f9-9a8f-9032aa4de82b.bmp[/img]

GetPublicJREHome函数的逻辑就是先查找

HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment\CurrentVersion

键值“当前JRE版本号”,然后取HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment\“当前JRE版本号”\JavaHome的路径所在 为JRE路径。


[b]小验证:[/b]

打开DEBUG,执行java -ersion,得到:

----_JAVA_LAUNCHER_DEBUG----

Version major.minor.micro = 1.6.0

JRE path is E:\Java\jre1.6.0

.............................


执行javac,得到:

----_JAVA_LAUNCHER_DEBUG----

JRE path is E:\Java\jdk1.6.0\jre

..................

这里要思考的是:为什么2者不一样呢??


其实,逻辑还是上面的那一套逻辑,只是忽略的一点是,在我们安装JDK的时候,会拷贝一份java.exe到C:\WINDOWS\system32\下,系统的Path目录包含了该目录,且先于我们配置的JAVA目录,所以,执行java -ersion的时候使用的是Windows目录下的那个java.exe而不是JAVA目录下的,所以导致走的PublicJRE的那个路径。


(2)、获取当前环境需要装载的jvm.dll文件路径:
要获取本机平台上应该使用哪个jvm.dll,是先通过java.c的ReadKnownVMs方法获取当前主机的jvm.cfg.该函数逻辑就是构造“JRE路径+\lib+\ARCH(CPU构架)+\jvm.cfg”路径。(ARCH的值是通过java_md.c的GetArch实现的。)

[code="c"]GetArch()
{
#ifdef _M_AMD64
return "amd64";
#elif defined(_M_IA64)
return "ia64";
#else
return "i386";
#endif
}[/code]


jvm.cfg文件的格式如下:

#

# @(#)jvm.cfg 1.8 05/11/17

#

# Copyright 2006 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


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替代而直接抛出错误信息。

加载完jvm.cfg文件之后,java.c会调用CheckJvmType方法去检测本机应该使用哪一个类型的JVM。该方法会首先判断用户是否有指定JVM类型,如果有就从前加载的jvm.cfg的数据中查找是否有用户指定的类型。如果用户指定的类型不合法,会抛异常。如果用户没有指定JVM类型,则直接返回jvm.cfg的第一项。

用户可以通过4种方式指定jvm的类型,“按照jvm.cfg文件中的jvm名称指定”,“java -J”、“java -XXaltjvm=”和“java -J-XXaltjvm=”。

获取到JVM的类型之后,进程会通过java_md.c的GetJVMPath的方法,把前面获取的JREPath,JVMType一起组成jvm.dll的绝对路径“JRE路径+\bin+\jvm类型字符串+\jvm.dll”。


以上是我个人学习总结所得,可能会有很多理解偏颇之处,欢迎指正探讨,也让我不要在错误的道路上越走越远,谢谢,龙年吉祥。


参考文章:http://zhidao.baidu.com/question/5956019

http://blog.163.com/irene_lwx@126/blog/static/28064560200792864055915/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值