文章詳情頁(yè)
java源代碼分析----jvm.dll裝載過(guò)程
瀏覽:73日期:2024-06-07 09:42:44
內(nèi)容: 簡(jiǎn)述眾所周知java.exe是java class文件的執(zhí)行程序,但實(shí)際上java.exe程序只是一個(gè)執(zhí)行的外殼,它會(huì)裝載jvm.dll(windows下,以下皆以windows平臺(tái)為例,linux下和solaris下其實(shí)類(lèi)似,為:libjvm.so),這個(gè)動(dòng)態(tài)連接庫(kù)才是java虛擬機(jī)的實(shí)際操作處理所在。本文探究java.exe程序是如何查找和裝載jvm.dll動(dòng)態(tài)庫(kù),并調(diào)用它進(jìn)行class文件執(zhí)行處理的。源代碼本文分析之代碼,《JavaTM 2 SDK, Standard Edition, v1.4.2 fcsCommunity Source Release》,可從sun官方網(wǎng)站下載,主要分析的源代碼為:j2sesrcsharebinjava.cj2sesrcwindowsbinjava_md.cjava.c是什么東西‘java程序’源代碼所謂‘java程序’,包括jdk中的java.exejavac.exejavadoc.exe,java.c源代碼中通過(guò)JAVA_ARGS宏來(lái)控制生成的代碼,如果該宏沒(méi)定義則編譯文件控制生成java.exe否則編譯文件控制生成其他的‘java程序’。比如:j2semakejavajavacMakefile(這是javac編譯文件)中:$(CD) ../../sun/javac ; $(MAKE) $@ RELEASE=$(RELEASE) FULL_VERSION=$(FULL_VERSION)j2semakesunjavacjavacMakefile(由上面Makefile文件調(diào)用)中:JAVA_ARGS = '{ '-J-ms8m', 'com.sun.tools.javac.Main' }'則由同一份java.c代碼生成的javac.exe程序就會(huì)直接調(diào)用java類(lèi)方法:com.sun.tools.javac.Main,這樣使其執(zhí)行起來(lái)就像是直接運(yùn)行的一個(gè)exe文件,而未定義JAVA_ARGS的java.exe程序則會(huì)調(diào)用傳遞過(guò)來(lái)參數(shù)中的類(lèi)方法。從java.c的main入口函數(shù)說(shuō)起main()函數(shù)中前面一段為重新分配參數(shù)指針的處理。然后調(diào)用函數(shù):CreateExecutionEnvironment,該函數(shù)主要查找java運(yùn)行環(huán)境的目錄,和jvm.dll這個(gè)虛擬機(jī)核心動(dòng)態(tài)連接庫(kù)文件路徑所在。根據(jù)操作系統(tǒng)不同,該函數(shù)有不同實(shí)現(xiàn)版本,但大體處理邏輯相同,我們看看windows平臺(tái)該函數(shù)的處理(j2sesrcwindowsbinjava_md.c)。CreateExecutionEnvironment函數(shù)主要分為三步處理:a、查找jre路徑。b、裝載jvm.cfg中指定的虛擬機(jī)動(dòng)態(tài)連接庫(kù)(jvm.dll)參數(shù)。c、取jvm.dll文件路徑。實(shí)現(xiàn):a、查找jre路徑是通過(guò)java_md.c中函數(shù):GetJREPath實(shí)現(xiàn)的。該函數(shù)首先調(diào)用GetApplicationHome函數(shù),GetApplicationHome函數(shù)調(diào)用windowsAPI函數(shù)GetModuleFileName取java.exe程序的絕對(duì)路徑,以我的jdk安裝路徑為例,為:“D:javaj2sdk1.4.2_04binjava.exe,然后去掉文件名取絕對(duì)路徑為:“D:javaj2sdk1.4.2_04bin,之后會(huì)在去掉最后一級(jí)目錄,現(xiàn)在絕對(duì)路徑為:“D:javaj2sdk1.4.2_04。然后GetJREPath函數(shù)繼續(xù)判斷剛剛?cè)〉穆窂?binjava.dll組合成的這個(gè)java.dll文件是否存在,如果存在則“D:javaj2sdk1.4.2_04為JRE路徑,否則判斷取得的“D:javaj2sdk1.4.2_04路徑+jrebinjava.dll文件是否存在,存在則“D:javaj2sdk1.4.2_04jre為JRE路徑。如果上面兩種情況都不存在,則從注冊(cè)表中去查找(參見(jiàn)函數(shù)GetPublicJREHome)。函數(shù):GetPublicJREHome先查找HKEY_LOCAL_MACHINESoftwareJavaSoftJava Runtime EnvironmentCurrentVersion鍵值“當(dāng)前JRE版本號(hào),判斷“當(dāng)前JRE版本號(hào)是否為1.4做為版本號(hào),如果是則取HKEY_LOCAL_MACHINESoftwareJavaSoftJava Runtime Environment“當(dāng)前JRE版本號(hào)JavaHome的路徑所在為JRE路徑。我的JDK返回的JRE路徑為:“D:javaj2sdk1.4.2_04jre。b、裝載jvm.cfg虛擬機(jī)動(dòng)態(tài)連接庫(kù)配置文件是通過(guò)java.c中函數(shù):ReadKnownVMs實(shí)現(xiàn)的。該函數(shù)首先組合jvm.cfg文件的絕對(duì)路徑,JRE路徑+lib+ARCH(CPU構(gòu)架)+jvm.cfgARCH(CPU構(gòu)架)的判斷是通過(guò)java_md.c中GetArch函數(shù)判斷的,該函數(shù)中windows平臺(tái)只有兩種情況:WIN64的‘ia64’,其他情況都為‘i386’。我的為i386所以jvm.cfg文件絕對(duì)路徑為:“D:javaj2sdk1.4.2_04jrelibi386jvm.cfg。文件內(nèi)容如下:## @(#)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(如果細(xì)心的話(huà),我們會(huì)發(fā)現(xiàn)在JDK目錄中我的為:“D:javaj2sdk1.4.2_04jrebinclient和“D:javaj2sdk1.4.2_04jrebinserver兩個(gè)目錄下都存在jvm.dll文件。而java正是通過(guò)jvm.cfg配置文件來(lái)管理這些不同版本的jvm.dll的。)ReadKnownVMs函數(shù)會(huì)將該文件中的配置內(nèi)容讀入到一個(gè)JVM配置結(jié)構(gòu)的全局變量中,該函數(shù)首先跳過(guò)注釋?zhuān)ㄒ?lsquo;#’開(kāi)始的行),然后讀取以‘-’開(kāi)始的行指定的jvm參數(shù),每一行為一個(gè)jvm信息,第一部分為jvm虛擬機(jī)名稱(chēng),第二部分為配置參數(shù),比如行:“-client KNOWN則“-client為虛擬機(jī)名稱(chēng),而“KNOWN為配置類(lèi)型參數(shù),“KNOWN表示該虛擬機(jī)的jvm.dll存在,而“ALIASED_TO表示為另一個(gè)jvm.dll的別名,“WARN表示該虛擬機(jī)的jvm.dll不存在但運(yùn)行時(shí)會(huì)用其他存在的jvm.dll替代執(zhí)行,而“ERROR同樣表示該類(lèi)虛擬機(jī)的jvm.dll不存在且運(yùn)行時(shí)不會(huì)找存在的jvm.dll替代而直接拋出錯(cuò)誤信息。在運(yùn)行java程序時(shí)指定使用那個(gè)虛擬機(jī)的判斷是由java.c中函數(shù):CheckJvmType判斷,該函數(shù)會(huì)檢查java運(yùn)行參數(shù)中是否有指定jvm的參數(shù),然后從ReadKnownVMs函數(shù)讀取的jvm.cfg數(shù)據(jù)結(jié)構(gòu)中去查找,從而指定不同的jvm類(lèi)型(最終導(dǎo)致裝載不同jvm.dll)。有兩種方法可以指定jvm類(lèi)型,一種按照jvm.cfg文件中的jvm名稱(chēng)指定,第二種方法是直接指定,它們執(zhí)行的方法分別是“java -J、“java -XXaltjvm=或“java -J-XXaltjvm=。如果是第一種參數(shù)傳遞方式,CheckJvmType函數(shù)會(huì)取參數(shù)‘-J’后面的jvm名稱(chēng),然后從已知的jvm配置參數(shù)中查找如果找到同名的則去掉該jvm名稱(chēng)前的‘-’直接返回該值;而第二種方法,會(huì)直接返回“-XXaltjvm=或“-J-XXaltjvm=后面的jvm類(lèi)型名稱(chēng);如果在運(yùn)行java時(shí)未指定上面兩種方法中的任一一種參數(shù),CheckJvmType會(huì)取配置文件中第一個(gè)配置中的jvm名稱(chēng),去掉名稱(chēng)前面的‘-’返回該值。CheckJvmType函數(shù)的這個(gè)返回值會(huì)在下面的函數(shù)中匯同jre路徑組合成jvm.dll的絕對(duì)路徑。比如:如果在運(yùn)行java程序時(shí)使用“java -J-client test則ReadKnownVMs會(huì)讀取參數(shù)“-client然后查找jvm.cfg讀入的參數(shù)中是否有jvm名稱(chēng)為“-client的,如果有則去掉jvm名稱(chēng)前的“-直接返回“client;而如果在運(yùn)行java程序時(shí)使用如下參數(shù):“java -XXaltjvm=D:javaj2sdk1.4.2_04jrebinclient test,則ReadKnownVMs會(huì)直接返回“D:javaj2sdk1.4.2_04jrebinclient;如果不帶上面參數(shù)執(zhí)行如:“java test,因?yàn)樵趈vm.cfg配置文件中第一個(gè)存在的jvm為“-client,所以函數(shù)ReadKnownVMs也會(huì)去掉jvm名稱(chēng)前的“-返回“client。其實(shí)這三中情況都是使用的“D:javaj2sdk1.4.2_04jrebinclientjvm.dll這個(gè)jvm動(dòng)態(tài)連接庫(kù)處理test這個(gè)class的,見(jiàn)下面GetJVMPath函數(shù)。c、取jvm.dll文件路徑是通過(guò)java_md.c中函數(shù):GetJVMPath實(shí)現(xiàn)的。由上面兩步我們已經(jīng)獲得了JRE路徑和jvm的類(lèi)型字符串。GetJVMPath函數(shù)判斷CheckJvmType返回的jvm類(lèi)型字符串中是否包含了‘’或‘/’如果包含則以該jvm類(lèi)型字符串+jvm.dll作為JVM的全路徑,否則以JRE路徑+bin+jvm類(lèi)型字符串+jvm.dll作為JVM的全路徑。看看上面的例子,第一種情況“java -J-client testjvm.dll路徑為:JRE路徑+bin+jvm類(lèi)型字符串+jvm.dll 按照我的JDK路徑則為:“D:javaj2sdk1.4.2_04jre+“bin+“client+“jvm.dll。第二種情況“java -XXaltjvm=D:javaj2sdk1.4.2_04jrebinclient test路徑為:jvm類(lèi)型字符串+jvm.dll即為:“D:javaj2sdk1.4.2_04jrebinclient+“jvm.dll第三種情況“java test為:“D:javaj2sdk1.4.2_04jre+“bin+“client+“jvm.dll與情況一相同。所以這三種情況都是調(diào)用的jvm動(dòng)態(tài)連接庫(kù)“D:javaj2sdk1.4.2_04jrebinclientjvm.dll處理test類(lèi)的。我們來(lái)進(jìn)一步驗(yàn)證一下:打開(kāi)cmd控制臺(tái):設(shè)置java裝載調(diào)試E:workjava_research>set _JAVA_LAUNCHER_DEBUG=1情況一E:workjava_research>java -J-client test.ScanDirectory----_JAVA_LAUNCHER_DEBUG----JRE path is D:javaj2sdk1.4.2_04jrejvm.cfg[0] = ->-client-server-hotspot-classic-native-greenjava test.ScanDirectory----_JAVA_LAUNCHER_DEBUG----JRE path is D:javaj2sdk1.4.2_04jrejvm.cfg[0] = ->-client-server-hotspot-classic-native-greenjava -XXaltjvm=D:javaj2sdk1.4.2_04jrebinserver test.ScanDirectory----_JAVA_LAUNCHER_DEBUG----JRE path is D:javaj2sdk1.4.2_04jrejvm.cfg[0] = ->-client-server-hotspot-classic-native-green
標(biāo)簽:
Java
上一條:java虛擬機(jī)詳述-第一章下一條:Java Socket編程
相關(guān)文章:
1. python中scrapy處理項(xiàng)目數(shù)據(jù)的實(shí)例分析2. 教你在 IntelliJ IDEA 中使用 VIM插件的詳細(xì)教程3. IntelliJ IDEA導(dǎo)入jar包的方法4. js抽獎(jiǎng)轉(zhuǎn)盤(pán)實(shí)現(xiàn)方法分析5. Python requests庫(kù)參數(shù)提交的注意事項(xiàng)總結(jié)6. vue-electron中修改表格內(nèi)容并修改樣式7. iOS實(shí)現(xiàn)點(diǎn)贊動(dòng)畫(huà)特效8. 通過(guò)Python pyecharts輸出保存圖片代碼實(shí)例9. JavaScript中l(wèi)ayim之整合右鍵菜單的示例代碼10. SpringBoot參數(shù)校驗(yàn)與國(guó)際化使用教程
排行榜
