熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

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

2013-11-23 19:22:55  來源: Java核心技術 

  簡述
  
  眾所周知javaexe是java class文件的執行程序但實際上javaexe程序只是
  一個執行的外殼它會裝載jvmdll(windows下以下皆以windows平台為例
  linux下和solaris下其實類似libjvmso)這個動態連接庫才是java
  虛擬機的實際操作處理所在本文探究javaexe程序是如何查找和裝載jvmdll
  動態庫並調用它進行class文件執行處理的
  
  源代碼
  
  本文分析之代碼《JavaTM SDK Standard Edition v fcs
  Community Source Release》可從sun官方網站下載主要分析的源代碼為
  jse\src\share\bin\javac
  jse\src\windows\bin\java_mdc
  
  javac是什麼東西
  
  java程序源代碼
  所謂java程序包括jdk中的javaexe\javacexe\javadocexejavac源
  代碼中通過JAVA_ARGS宏來控制生成的代碼如果該宏沒定義則編譯文件控制生
  成javaexe否則編譯文件控制生成其他的java程序
  比如
  jse\make\java\javac\Makefile(這是javac編譯文件)中
  $(CD) //sun/javac ; $(MAKE) $@ RELEASE=$(RELEASE) FULL_VERSION=$(FULL_VERSION)
  jse\make\sun\javac\javac\Makefile(由上面Makefile文件調用)中
  JAVA_ARGS = { \Jmsm\ \comsuntoolsjavacMain\ }
  則由同一份javac代碼生成的javacexe程序就會直接調用java類方法
  comsuntoolsjavacMain這樣使其執行起來就像是直接運行的一個exe文件
  而未定義JAVA_ARGS的javaexe程序則會調用傳遞過來參數中的類方法
  
  從javac的main入口函數說起
  
  main()函數中前面一段為重新分配參數指針的處理
  然後調用函數CreateExecutionEnvironment該函數主要查找java運行環境的
  目錄和jvmdll這個虛擬機核心動態連接庫文件路徑所在根據操作系統不同
  該函數有不同實現版本但大體處理邏輯相同我們看看windows平台該函數的處
  理(jse\src\windows\bin\java_mdc)
  
  CreateExecutionEnvironment函數主要分為三步處理
  a查找jre路徑
  b裝載jvmcfg中指定的虛擬機動態連接庫(jvmdll)參數
  c取jvmdll文件路徑
  
  實現
  
  a查找jre路徑是通過java_mdc中函數GetJREPath實現的
  該函數首先調用GetApplicationHome函數GetApplicationHome函數調用windows
  API函數GetModuleFileName取javaexe程序的絕對路徑以我的jdk安裝路徑為例
  為D:\java\jsdk_\bin\javaexe然後去掉文件名取絕對路徑為
  D:\java\jsdk_\bin之後會在去掉最後一級目錄現在絕對路徑為
  D:\java\jsdk_
  然後GetJREPath函數繼續判斷剛剛取的路徑+\bin\javadll組合成的這個javadll
  文件是否存在如果存在則D:\java\jsdk_為JRE路徑否則判斷取得
  的D:\java\jsdk_路徑+\jre\bin\javadll文件是否存在存在則
  D:\java\jsdk_\jre為JRE路徑如果上面兩種情況都不存在則從注
  冊表中去查找(參見函數GetPublicJREHome)
  
  函數GetPublicJREHome先查找
  HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment\CurrentVersion
  鍵值當前JRE版本號判斷當前JRE版本號是否為做為版本號如果是則
  取HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment\當前JRE版本號
  \JavaHome的路徑所在為JRE路徑
  
  我的JDK返回的JRE路徑為D:\java\jsdk_\jre
  
  b裝載jvmcfg虛擬機動態連接庫配置文件是通過javac中函數:ReadKnownVMs實現
  的
  該函數首先組合jvmcfg文件的絕對路徑JRE路徑+\lib+\ARCH(CPU構架)+\jvmcfg
  ARCH(CPU構架)的判斷是通過java_mdc中GetArch函數判斷的該函數中windows平
  台只有兩種情況WINia其他情況都為i我的為i所以jvmcfg
  文件絕對路徑為D:\java\jsdk_\jre\lib\i\jvmcfg文件內容如
  下
  ## @(#)jvmcfg  //# # Copyright 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 KNOWNserver KNOWNhotspot ALIASED_TO clientclassic WARNnative ERRORgreen ERROR
  
  (如果細心的話我們會發現在JDK目錄中我的為D:\java\jsdk_\jre\bin\clientD:\java\jsdk_\jre\bin\server兩個目錄下都存在jvmdll文件而java正是通過jvmcfg配置文件來管理這些不同版本的jvmdll的
  
  ReadKnownVMs函數會將該文件中的配置內容讀入到一個JVM配置結構的全局變量中該函數首先跳過注釋(以#開始的行)然後讀取以開始的行指定的jvm參數每一行為一個jvm信息第一部分為jvm虛擬機名稱第二部分為配置參數比如行
  client KNOWNclient為虛擬機名稱KNOWN為配置類型參數KNOWN
  表示該虛擬機的jvmdll存在ALIASED_TO表示為另一個jvmdll的別名WARN
  表示該虛擬機的jvmdll不存在但運行時會用其他存在的jvmdll替代執行ERROR
  同樣表示該類虛擬機的jvmdll不存在且運行時不會找存在的jvmdll替代而直接拋出錯誤
  信息
  
  在運行java程序時指定使用那個虛擬機的判斷是由javac中函數CheckJvmType判斷該函數會檢查java運行參數中是否有指定jvm的參數然後從ReadKnownVMs函數讀取的jvmcfg數據結構中去查找從而指定不同的jvm類型(最終導致裝載不同jvmdll)有兩種方法可以指定jvm類型一種按照jvmcfg文件中的jvm名稱指定第二種方法是直接指定它們執行的方法分別是java J<jvmcfg中jvm名稱>java XXaltjvm=<jvm類型名稱>java JXXaltjvm=<jvm類型名稱>如果是第一種參數傳遞方式CheckJvmType函數會取參數J後面的jvm名稱然後從已知的jvm配置參數中查找如果找到同名的則去掉該jvm名稱前的直接返回該值而第二種方法會直接返回XXaltjvm=JXXaltjvm=後面的jvm類型名稱如果在運行java時未指定上面兩種方法中的任一一種參數CheckJvmType會取配置文件中第一個配置中的jvm名稱去掉名稱前面的返回該值CheckJvmType函數的這個返回值會在下面的函數中匯同jre路徑組合成jvmdll的絕對路徑
  
  比如如果在運行java程序時使用java Jclient test則ReadKnownVMs會讀取參數client然後查找jvmcfg讀入的參數中是否有jvm名稱為client如果有則去掉jvm名稱前的直接返回client而如果在運行java程序時使用如下參數
  java XXaltjvm=D:\java\jsdk_\jre\bin\client test則ReadKnownVMs
  會直接返回D:\java\jsdk_\jre\bin\client如果不帶上面參數執行如
  java test因為在jvmcfg配置文件中第一個存在的jvm為client所以函數
  ReadKnownVMs也會去掉jvm名稱前的返回client其實這三中情況都是使用的
  D:\java\jsdk_\jre\bin\client\jvmdll這個jvm動態連接庫處理test這個class的見下面GetJVMPath函數
  
  c取jvmdll文件路徑是通過java_mdc中函數GetJVMPath實現的
  由上面兩步我們已經獲得了JRE路徑和jvm的類型字符串GetJVMPath函數判斷CheckJvmType
  返回的jvm類型字符串中是否包含了\/如果包含則以該jvm類型字符串+\jvmdll作為JVM的全路徑否則以JRE路徑+\bin+\jvm類型字符串+\jvmdll作為JVM的全路徑
  
  看看上面的例子第一種情況java Jclient testjvmdll路徑為
  JRE路徑+\bin+\jvm類型字符串+\jvmdll 按照我的JDK路徑則為
  D:\java\jsdk_\jre+\bin+\client+\jvmdll
  第二種情況java XXaltjvm=D:\java\jsdk_\jre\bin\client test路徑為
  jvm類型字符串+\jvmdll即為D:\java\jsdk_\jre\bin\client+\jvmdll
  第三種情況java testD:\java\jsdk_\jre+\bin+\client
  +\jvmdll與情況一相同所以這三種情況都是調用的jvm動態連接庫D:\javajsdk_\jre\bin\client\jvmdll處理test類的
  
  我們來進一步驗證一下
  打開cmd控制台
  
  設置java裝載調試
  E:\work\java_research>set _JAVA_LAUNCHER_DEBUG=
  
  情況一
  E:\work\java_research>java Jclient testScanDirectory
  _JAVA_LAUNCHER_DEBUG

From:http://tw.wingwit.com/Article/program/Java/hx/201311/26750.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.