1. 程式人生 > >JVM的工作原理,我只是簡單的說下,不知道對不對!

JVM的工作原理,我只是簡單的說下,不知道對不對!

        在Java中引入了虛擬機器的概念,即在機器和編譯程式之間加入了一層抽象的虛擬的機器。這臺虛擬的機器在任何平臺上都提供給編譯程式一個的共同的介面。編譯程式只需要面向虛擬機器,生成虛擬機器能夠理解的程式碼,然後由直譯器來將虛擬機器程式碼轉換為特定系統的機器碼執行。在Java中,這種供虛擬機器理解的程式碼叫做位元組碼(ByteCode),它不面向任何特定的處理器,只面向虛擬機器。每一種平臺的直譯器是不同的,但是實現的虛擬機器是相同的。Java源程式經過編譯器編譯後變成位元組碼,位元組碼由虛擬機器解釋執行,虛擬機器將每一條要執行的位元組碼送給直譯器,直譯器將其翻譯成特定機器上的機器碼,然後在特定的機器上執行。

作業系統裝入jvm是通過jdk中java.exe來完成,通過下面4步來完成jvm環境.

1.建立jvm裝載環境和配置

2.裝載jvm.dll

 3.初始化jvm.dll並掛界到JNIENV(JNI呼叫介面)例項

4.呼叫JNIEnv例項裝載並處理class類。

        一.jvm裝入環境,jvm提供的方式是作業系統的動態連線檔案.既然是檔案那就一個裝入路徑的問題,java是怎麼找這個路徑的呢?當你在呼叫java test的時候,作業系統會在path下在你的java.exe程式,java.exe就通過下面一個過程來確定jvm的路徑和相關的引數配置了.下面基於windows的實現的分析. 首先查詢jre路徑,java是通過GetApplicationHome api來獲得當前的java.exe絕對路徑,c:/j2sdk1.4.2_09/bin/java.exe,那麼它會擷取到絕對路徑c:/j2sdk1.4.2_09/,判斷c:/j2sdk1.4.2_09/bin/java.dll檔案是否存在,如果存在就把c:/j2sdk1.4.2_09/作為jre路徑,如果不存在則判斷c:/j2sdk1.4.2_09/jre/bin/java.dll是否存在,如果存在這c:/j2sdk1.4.2_09/jre作為jre路徑.如果不存在呼叫GetPublicJREHome查HKEY_LOCAL_MACHINE/Software/JavaSoft/Java Runtime Environment/“當前JRE版本號”/JavaHome的路徑為jre路徑。 然後裝載jvm.cfg檔案JRE路徑+/lib+/ARCH(CPU構架)+/jvm.cfgARCH(CPU構架)的判斷是通過java_md.c中GetArch函式判斷的,該函式中windows平臺只有兩種情況:WIN64的‘ia64’,其他情況都為‘i386’。以我的為例:C:/j2sdk1.4.2_09/jre/lib/i386/jvm.cfg.主要的內容如下: -client KNOWN -server KNOWN -hotspot ALIASED_TO -client -classic WARN -native ERROR -green ERROR 在我們的jdk目錄中jre/bin/server和jre/bin/client都有jvm.dll檔案存在,而java正是通過jvm.cfg配置檔案來管理這些不同版本的jvm.dll的.通過檔案我們可以定義目前jdk中支援那些jvm,前面部分(client)是jvm名稱,後面是引數,KNOWN表示jvm存在,ALIASED_TO表示給別的jvm取一個別名,WARN表示不存在時找一個jvm替代,ERROR表示不存在丟擲異常.在執行java XXX是,java.exe會通過CheckJvmType來檢查當前的jvm型別,java可以通過兩種引數的方式來指定具體的jvm型別,一種按照jvm.cfg檔案中的jvm名稱指定,第二種方法是直接指定,它們執行的方法分別是“java -J”、“java -XXaltjvm=”或“java -J-XXaltjvm=”。如果是第一種引數傳遞方式,CheckJvmType函式會取引數‘-J’後面的jvm名稱,然後從已知的jvm配置引數中查詢如果找到同名的則去掉該jvm名稱前的‘-’直接返回該值;而第二種方法,會直接返回“-XXaltjvm=”或“-J-XXaltjvm=”後面的jvm型別名稱;如果在執行java時未指定上面兩種方法中的任一一種引數,CheckJvmType會取配置檔案中第一個配置中的jvm名稱,去掉名稱前面的‘-’返回該值。CheckJvmType函式的這個返回值會在下面的函式中匯同jre路徑組合成jvm.dll的絕對路徑。如果沒有指定這會使用jvm.cfg中第一個定義的jvm.可以通過set _JAVA_LAUNCHER_DEBUG=1在控制檯上測試. 最後獲得jvm.dll的路徑,JRE路徑+/bin+/jvm型別字串+/jvm.dll就是jvm的檔案路徑了,但是如果在呼叫java程式時用-XXaltjvm=引數指定的路徑path,就直接用path+/jvm.dll檔案做為jvm.dll的檔案路徑.

        二:裝載jvm.dll 通過第一步已經找到了jvm的路徑,java通過LoadJavaVM來裝入jvm.dll檔案.裝入工作很簡單就是呼叫windows API函式: LoadLibrary裝載jvm.dll動態連線庫.然後把jvm.dll中的匯出函式JNI_CreateJavaVM和JNI_GetDefaultJavaVMInitArgs掛接到InvocationFunctions變數的CreateJavaVM和GetDefaultJavaVMInitArgs函式指標變數上。jvm.dll的裝載工作宣告完成。

        三:初始化jvm,獲得本地呼叫介面,這樣就可以在java中呼叫jvm的函數了.呼叫InvocationFunctions->CreateJavaVM也就是jvm中JNI_CreateJavaVM方法獲得JNIEnv結構的例項.

        四:執行java程式. java程式有兩種方式一種是jar包,一種是class. 執行jar,java -jar XXX.jar執行的時候,java.exe呼叫GetMainClassName函式,該函式先獲得JNIEnv例項然後呼叫java類java.util.jar.JarFileJNIEnv中方法getManifest()並從返回的Manifest物件中取getAttributes("Main-Class")的值即jar包中檔案:META-INF/MANIFEST.MF指定的Main-Class的主類名作為執行的主類。之後main函式會呼叫java.c中LoadClass方法裝載該主類(使用JNIEnv例項的FindClass)。main函式直接呼叫java.c中LoadClass方法裝載該類。如果是執行class方法。main函式直接呼叫java.c中LoadClass方法裝載該類。