-
問 JVM包含哪幾部分项鬼?
JVM 主要由四大部分組成:ClassLoader(類加載器)粱栖,Runtime Data Area(運(yùn)行時(shí)數(shù)據(jù)區(qū),內(nèi)存分區(qū)),Execution Engine(執(zhí)行引擎)斜姥,Native Interface(本地庫接口)匈辱,下圖可以大致描述JVM的結(jié)構(gòu)
JVM的結(jié)構(gòu)
JVM是執(zhí)行Java程序的虛擬計(jì)算機(jī)系統(tǒng)部翘,執(zhí)行過程: 首先需要準(zhǔn)備好編譯好的Java字節(jié)碼文件(即class文件)河闰,計(jì)算機(jī)要運(yùn)行程序需要先通過一定方式(類加載器)將class文件加載到內(nèi)存中(運(yùn)行時(shí)數(shù)據(jù)區(qū)),但是字節(jié)碼文件是JVM定義的一套指令集規(guī)范锨匆,并不能直接交給底層操作系統(tǒng)去執(zhí)行崭别,因此需要特定的命令解釋器(執(zhí)行引擎)將字節(jié)碼翻譯成特定的操作系統(tǒng)指令集交給CPU去執(zhí)行,這個(gè)過程中需要調(diào)用一些不同語言為Java提供的接口(例如驅(qū)動(dòng)恐锣,地圖制作等)茅主,這就用到了本地native接口(本地庫接口)
ClassLoader:負(fù)責(zé)加載字節(jié)碼文件即class文件,class文件在文件開頭有特定的文件標(biāo)示土榴,并且ClassLoader只負(fù)責(zé)class文件的加載诀姚,至于是否可以運(yùn)行,則由Execution Engine決定
Runtime Data Area:是存放數(shù)據(jù)的玷禽,分為五部分:Stack(虛擬機(jī)棧)赫段,Heap(堆),Method Area(方法區(qū))矢赁,PC Register(程序計(jì)數(shù)器)糯笙,Native Method Stack(本地方法棧)。幾乎所有的關(guān)于Java內(nèi)存方面的問題坯台,都集中在這塊炬丸。
Execution Engine:執(zhí)行引擎,也叫 Interpreter蜒蕾。Class文件被加載后,會(huì)把指令和數(shù)據(jù)信息放入內(nèi)存中焕阿,Execution Engine則負(fù)責(zé)把這些命令解釋給操作系統(tǒng)咪啡,即將JVM指令集翻譯為操作系統(tǒng)的指令集。
Native Interface:負(fù)責(zé)調(diào)用本地接口的暮屡,他的作用是調(diào)用不同語言的接口給Java用撤摸,他會(huì)在Native Method Stack中記錄對(duì)應(yīng)的本地方法,然后調(diào)用該方法時(shí)就通過Execution Engine加載對(duì)應(yīng)的本地lib褒纲。原本多用于一些專業(yè)領(lǐng)域准夷,如Java驅(qū)動(dòng),地圖制作引擎等莺掠,現(xiàn)在關(guān)于這種本地方法接口的調(diào)用已經(jīng)被類似于Socket通信衫嵌,WebService等方式取代。 JVM的啟動(dòng)過程分為如下四個(gè)步驟:
- JVM的裝入環(huán)境和配置
java.exe 負(fù)責(zé)查找JRE,并且它會(huì)按照如下的順序來選擇JRE
自己目錄下的JRE
父級(jí)目錄下的JRE
查注冊(cè)中注冊(cè)的JRE - 裝載JVM
通過第一步找到JVM的路徑后彻秆,Java.exe通過LoadJavaVM來裝入JVM文件楔绞。LoadLibrary裝載JVM動(dòng)態(tài)連接庫结闸,然后把JVM中的到處函數(shù)JNI_CreateJavaVM和JNI_GetDefaultJavaVMIntArgs掛接到InvocationFunction變量的CreateJavaVM和GetDefaultJavaVMInitArgs函數(shù)指針變量上。JVM的裝載工作完成 - 初始化JVM,獲得本地調(diào)用接口
調(diào)用InvocationFunction->CreateJavaVM酒朵,也就是JVM中JNI_CreateJavaVM方法獲得JNIEnv結(jié)構(gòu)的實(shí)例 - 運(yùn)行Java程序
JVM運(yùn)行Java程序的方式有兩種:jar包和class
運(yùn)行jar的時(shí)候桦锄,java.exe調(diào)用GetMainClassName函數(shù),該函數(shù)先獲得JNIEnv實(shí)例然后調(diào)用JarFileJNIEnv類中g(shù)etManifest()蔫耽,從其返回的Manifest對(duì)象中取getAttrebutes(“Main-Class”)的值结耀,即jar包中文件:META-INF/MANIFEST.MF指定的Main-Class的主類名作為運(yùn)行的主類。之后main函數(shù)會(huì)調(diào)用Java.c中的LoadClass方法裝載該主類(使用JNIEnv實(shí)例的FindClass)
運(yùn)行Class的時(shí)候匙铡,main函數(shù)直接調(diào)用Java.c中的LoadClass方法裝載該類图甜。
-
Java程序是怎么運(yùn)行的?
寫好的Java源代碼經(jīng)過Java編譯器編譯成字節(jié)碼文件后慰枕,通過類加載器加載到內(nèi)存中具则,才能被實(shí)例化,然后Java虛擬機(jī)中解釋執(zhí)行后具帮,最后通過操作系統(tǒng)操作CPU執(zhí)行獲取結(jié)果博肋,如下圖
Java運(yùn)行過程