java運行過程

來源:互聯網
上載者:User

 

1。java概念
2。JRE版本控制
3。JRE類庫尋找
4。Java的虛擬機器啟動和載入類庫

 

 

1。java概念

Java
byte code (位元組碼)
jvm.dll (虛擬機器)
JRE (運行環境)
JDK (開發架構)
package (類庫) 

2。JRE版本控制

當在控制台執行java.exe,作業系統尋找JRE的方式如下:
1) 先找目前的目錄下有沒有JRE
2)再找父目錄下有沒有JRE
3)接著在PATH路徑中找JRE
4)註冊表HKEY_LOCAL_MACHINE/SOFTWARE/JavaSoft/Java Runtime Environment/ 查看CurrentVersion的索引值指向哪個JRE

//Windows平台java.exe調用jre過程//
===========================================
尋找jre路徑是通過java_md.c中函數:GetJREPath實現的。

<1>該函數首先調用GetApplicationHome函數,GetApplicationHome函數調用windowsAPI函數  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路徑。

 <2>如果上面兩種情況都不存在,則從註冊表中去尋找(參見函數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”。

3。JRE類庫尋找

JRE內建的基礎類庫主要是JRE/lib/rt.jar這個檔案,包括了Java2平台標準版的所有類庫。和JRE的版本一致。

JRE中由ClassLoader負責尋找和載入程式引用到的類庫,基礎類庫ClassLoader會到rt.jar中自動載入,其它的類庫,ClassLoader在環境變數CLASSPATH指定的路徑中搜尋,按照先來先到的原則,放在CLASSPATH前面的類庫先被搜到,Java程式啟動之前建議先把PATH和CLASSPATH環境變數設好,OS通過PATH來找JRE,確定基礎類庫rt.jar的位置,JRE的ClassLoader通過CLASSPATH找其它類庫。但有時候會出現這樣的情況,希望替換基礎類庫中的類庫,那麼也可以簡單的通過-Djava.endrosed.path=...參數傳遞給java.exe,於是ClassLoader會先於基礎類庫使用java.endrosed.path參數指定路徑的類庫。因此Java的版本管理是非常簡單有效,也許很原始,不過很好用,簡單就不容易出錯。

4。Java的虛擬機器啟動和載入類庫

在Console執行java.exe xxx命令以後,如前所述的尋找JRE,OS找到JRE目錄,根據java.exe的傳遞參數,選擇載入Server版的jvm.dll還是Client版的jvm.dll,然後載入jvm.dll,把控制權交給jvm.dll。

接下來,jvm.dll進行初始化,分配記憶體等等動作,然後在CLASSPATH路徑中尋找class,找到class以後,尋找class中的程式進入點Main函數,然後從Main函數執行程式,在執行過程中,使用ClassLoader動態載入一系列引用到的類。當調用到native方法時,jvm.dll告訴OS在JRE/bin目錄下尋找某某DLL檔案,調入記憶體,於是實現了JNI調用。

//Windows平台java.exe啟動jvm.dll的過程//
===========================================
<1>裝載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”。檔案內容如下:

<3>取jvm.dll檔案路徑是通過java_md.c中函數:GetJVMPath實現的。

由上面兩步我們已經獲得了JRE路徑和jvm的類型字串。GetJVMPath函數判斷CheckJvmType返回的jvm類型字串中是否包含了‘/’或‘/’如果包含則以該jvm類型字串+/jvm.dll作為JVM的全路徑,否則以JRE路徑+/bin+/jvm類型字串+/jvm.dll作為JVM的全路徑。

下面是3個例子:

看看上面的例子,

第一種情況“java -J-client test”jvm.dll路徑為:JRE路徑+/bin+/jvm類型字串+/jvm.dll 按照我的JDK路徑則為:“D:/java/j2sdk1.4.2_04/jre”+“/bin”+“/client”+“/jvm.dll”。

第二種情況“java -Xaltjvm=D:/java/j2sdk1.4.2_04/jre/bin/client test”路徑為:jvm類型字串+/jvm.dll即為:“:/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:/java/j2sdk1.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----

    JRE path is D:/java/j2sdk1.4.2_04/jre

    jvm.cfg[0] = ->-client<-

    jvm.cfg[1] = ->-server<-

    jvm.cfg[2] = ->-hotspot<-

    jvm.cfg[3] = ->-classic<-

    jvm.cfg[4] = ->-native<-

    jvm.cfg[5] = ->-green<-

    299 micro seconds to parse jvm.cfg

    JVM path is D:/java/j2sdk1.4.2_04/jre/bin/client/jvm.dll

    2897 micro seconds to LoadJavaVM

    JavaVM args:

        version 0x00010002, ignoreUnrecognized is JNI_FALSE, nOptions is 2

        option[ 0] = '-Djava.class.path=.'

        option[ 1] = '-Dsun.java.command=test.ScanDirectory'

    50001 micro seconds to InitializeJVM

    Main-Class is 'test.ScanDirectory'

    Apps' argc is 0

    10208 micro seconds to load main class

    ----_JAVA_LAUNCHER_DEBUG----

    usage: java test.ScanDirectory DIR [output file]

情況二

    E:/work/java_research>java -XXaltjvm=D:/java/j2sdk1.4.2_04/jre/bin/client test.ScanDirectory

    ----_JAVA_LAUNCHER_DEBUG----

    JRE path is D:/java/j2sdk1.4.2_04/jre

    jvm.cfg[0] = ->-client<-

    jvm.cfg[1] = ->-server<-

    jvm.cfg[2] = ->-hotspot<-

    jvm.cfg[3] = ->-classic<-

    jvm.cfg[4] = ->-native<-

    jvm.cfg[5] = ->-green<-

    386 micro seconds to parse jvm.cfg

    JVM path is D:/java/j2sdk1.4.2_04/jre/bin/client/jvm.dll

    2795 micro seconds to LoadJavaVM

    JavaVM args:

        version 0x00010002, ignoreUnrecognized is JNI_FALSE, nOptions is 2

        option[ 0] = '-Djava.class.path=.'

        option[ 1] = '-Dsun.java.command=test.ScanDirectory'

    49978 micro seconds to InitializeJVM

    Main-Class is 'test.ScanDirectory'

    Apps' argc is 0

    9598 micro seconds to load main class

    ----_JAVA_LAUNCHER_DEBUG----

    usage: java test.ScanDirectory DIR [output file]

情況三

    E:/work/java_research>java test.ScanDirectory

    ----_JAVA_LAUNCHER_DEBUG----

    JRE path is D:/java/j2sdk1.4.2_04/jre

    jvm.cfg[0] = ->-client<-

    jvm.cfg[1] = ->-server<-

    jvm.cfg[2] = ->-hotspot<-

    jvm.cfg[3] = ->-classic<-

    jvm.cfg[4] = ->-native<-

    jvm.cfg[5] = ->-green<-

    381 micro seconds to parse jvm.cfg

    JVM path is D:/java/j2sdk1.4.2_04/jre/bin/client/jvm.dll

    3038 micro seconds to LoadJavaVM

    JavaVM args:

        version 0x00010002, ignoreUnrecognized is JNI_FALSE, nOptions is 2

        option[ 0] = '-Djava.class.path=.'

        option[ 1] = '-Dsun.java.command=test.ScanDirectory'

    50080 micro seconds to InitializeJVM

    Main-Class is 'test.ScanDirectory'

    Apps' argc is 0

    10215 micro seconds to load main class

    ----_JAVA_LAUNCHER_DEBUG----

    usage: java test.ScanDirectory DIR [output file]

    三個的JVM路徑都為:

    JVM path is D:/java/j2sdk1.4.2_04/jre/bin/client/jvm.dll

其他情況

    E:/work/java_research>java -J-server test.ScanDirectory

    ----_JAVA_LAUNCHER_DEBUG----

    JRE path is D:/java/j2sdk1.4.2_04/jre

    jvm.cfg[0] = ->-client<-

    jvm.cfg[1] = ->-server<-

    jvm.cfg[2] = ->-hotspot<-

    jvm.cfg[3] = ->-classic<-

    jvm.cfg[4] = ->-native<-

    jvm.cfg[5] = ->-green<-

    377 micro seconds to parse jvm.cfg

    JVM path is D:/java/j2sdk1.4.2_04/jre/bin/server/jvm.dll

    2985 micro seconds to LoadJavaVM

    JavaVM args:

        version 0x00010002, ignoreUnrecognized is JNI_FALSE, nOptions is 2

        option[ 0] = '-Djava.class.path=.'

        option[ 1] = '-Dsun.java.command=test.ScanDirectory'

    62382 micro seconds to InitializeJVM

    Main-Class is 'test.ScanDirectory'

    Apps' argc is 0

    12413 micro seconds to load main class

    ----_JAVA_LAUNCHER_DEBUG----

    usage: java test.ScanDirectory DIR [output file]

    E:/work/java_research>java -XXaltjvm=D:/java/j2sdk1.4.2_04/jre/bin/server test.ScanDirectory

    ----_JAVA_LAUNCHER_DEBUG----

    JRE path is D:/java/j2sdk1.4.2_04/jre

    jvm.cfg[0] = ->-client<-

    jvm.cfg[1] = ->-server<-

    jvm.cfg[2] = ->-hotspot<-

    jvm.cfg[3] = ->-classic<-

    jvm.cfg[4] = ->-native<-

    jvm.cfg[5] = ->-green<-

    376 micro seconds to parse jvm.cfg

    JVM path is D:/java/j2sdk1.4.2_04/jre/bin/server/jvm.dll

    2937 micro seconds to LoadJavaVM

    JavaVM args:

        version 0x00010002, ignoreUnrecognized is JNI_FALSE, nOptions is 2

        option[ 0] = '-Djava.class.path=.'

        option[ 1] = '-Dsun.java.command=test.ScanDirectory'

    62725 micro seconds to InitializeJVM

    Main-Class is 'test.ScanDirectory'

    Apps' argc is 0

    8942 micro seconds to load main class

    ----_JAVA_LAUNCHER_DEBUG----

    usage: java test.ScanDirectory DIR [output file]

總結:

1。jre的尋找可以通過path路徑和java.exe檔案

2。也可以尋找註冊表尋找,如寫入下列註冊表檔案即可。

Windows Registry Editor Version 5.00

   

    [HKEY_LOCAL_MACHINE/SOFTWARE/JavaSoft]

   

    [HKEY_LOCAL_MACHINE/SOFTWARE/JavaSoft/Java Runtime Environment]

    "CurrentVersion"="1.4"

   

    [HKEY_LOCAL_MACHINE/SOFTWARE/JavaSoft/Java Runtime Environment/1.4]

    "JavaHome"="D://java//j2sdk1.4.2_04//jre"

 

 

 

   #

    # @(#)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=<jvm_dir>" 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”和“:/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存在,而“LIASED_TO”表示為另一個jvm.dll的別名,“WARN”表示該虛擬機器的jvm.dll不存在但運行時會用其他存在的jvm.dll替代執行,而“ERROR”同樣表示該類虛擬機器的jvm.dll不存在且運行時不會找存在的jvm.dll替代而直接拋出錯誤資訊。

  <2> 在運行java程式時指定使用那個虛擬機器的判斷是由java.c中函數:CheckJvmType判斷,該函數會檢查java運行參數中是否有指定jvm的參數,然後從ReadKnownVMs函數讀取的jvm.cfg資料結構中去尋找,從而指定不同的jvm類型(最終導致裝載不同jvm.dll)。有兩種方法可以指定jvm類型,一種按照jvm.cfg檔案中的jvm名稱指定,第二種方法是直接指定,它們執行的方法分別是“java -J<jvm.cfg中jvm名稱>”、“java
-XXaltjvm=<jvm類型名稱>”或“java -J-XXaltjvm=<jvm類型名稱>”。如果是第一種參數傳遞方式,CheckJvmType函數會取參數‘-J’後面的jvm名稱,然後從已知的jvm配置參數中尋找如果找到同名的則去掉該jvm名稱前的‘-’直接返回該值;而第二種方法,會直接返回“-XXaltjvm=”或“-J-XXaltjvm=”後面的jvm類型名稱;如果在運行java時未指定上面兩種方法中的任一一種參數,CheckJvmType會取設定檔中第一個配置中的jvm名稱,去掉名稱前面的‘-’返回該值。heckJvmType函數的這個傳回值會在下面的函數中匯同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函數。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.