国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

java源代碼分析----jvm.dll裝載過程

2019-11-18 12:14:17
字體:
來源:轉載
供稿:網友

  簡述
  
  眾所周知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=<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”和“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<jvm.cfg中jvm名稱>”、“java -XXaltjvm=<jvm類型名稱>”或“java -J-XXaltjvm=<jvm類型名稱>”。假如是第一種參數傳遞方式,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----

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 万载县| 大丰市| 安徽省| 榆树市| 鸡泽县| 调兵山市| 和硕县| 盈江县| 尚志市| 石渠县| 哈巴河县| 裕民县| 鸡西市| 平远县| 蒙山县| 揭西县| 阳新县| 余干县| 枞阳县| 孙吴县| 咸阳市| 辰溪县| 三明市| 沙雅县| 盈江县| 青浦区| 旅游| 南溪县| 建宁县| 乌苏市| 青岛市| 扶绥县| 宁城县| 贵州省| 盱眙县| 伊春市| 七台河市| 郯城县| 江都市| 临夏县| 汶川县|