JVM是什么
JVM全稱(chēng)Java Virtual Machine(Java虛擬機(jī)),是一個(gè)虛構(gòu)出來(lái)的計(jì)算機(jī),它屏蔽了與具體操作系統(tǒng)平臺(tái)相關(guān)的信息,使得Java程序只需生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼,ByteCode), 就可以在多種平臺(tái)上不加修改地運(yùn)行。這背后其實(shí)就是JVM把字節(jié)碼翻譯成具體平臺(tái)上的機(jī)器指令,從而實(shí)現(xiàn)“一次編寫(xiě),到處運(yùn)行(Write Once, Run Anywhere)”。
JVM架構(gòu)圖

JVM工作機(jī)制
如上面的架構(gòu)圖所示,JVM分成四個(gè)主要的子系統(tǒng):
- 類(lèi)加載器
- 運(yùn)行時(shí)數(shù)據(jù)區(qū)
- 執(zhí)行引擎
- 本地方法調(diào)用
類(lèi)加載器
Java的動(dòng)態(tài)類(lèi)加載功能由類(lèi)加載器子系統(tǒng)處理。它加載,鏈接,并在類(lèi)運(yùn)行時(shí)第一次引用類(lèi)時(shí)初始化類(lèi)文件,而不是編譯時(shí)。
1.1 加載
通過(guò)類(lèi)加載器實(shí)現(xiàn)類(lèi)的加載動(dòng)作,絕大部分Java程序都會(huì)使用到以下三種系統(tǒng)提供的類(lèi)加載器:
- 啟動(dòng)類(lèi)加載器(Bootstrap ClassLoader)
- 擴(kuò)展類(lèi)加載器(Extension ClassLoader)
- 應(yīng)用程序類(lèi)加載器(Application ClassLoader)
上面的類(lèi)加載器將在加載類(lèi)文件時(shí)遵循委托層次結(jié)構(gòu)算法。
1.2 鏈接
- 驗(yàn)證 確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害虛擬機(jī)自身的安全
- 準(zhǔn)備 正式為類(lèi)變量分配內(nèi)存并設(shè)置初始值的階段,這些變量所使用的內(nèi)存都將在方法區(qū)中進(jìn)行分配
- 解析 虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程
1.3 初始化
這是類(lèi)加載的最后階段,為所有的變量分配原始值,并執(zhí)行靜態(tài)代碼塊
運(yùn)行時(shí)數(shù)據(jù)區(qū)
Java虛擬機(jī)在運(yùn)行程序的過(guò)程中會(huì)把它所管理的內(nèi)存劃分為若干個(gè)不同的數(shù)據(jù)區(qū)。這些區(qū)域都有各自的用途,以及創(chuàng)建和銷(xiāo)毀的時(shí)間,有的區(qū)域隨著虛擬機(jī)進(jìn)程的啟動(dòng)而存在,有的區(qū)域則依賴用戶線程的啟動(dòng)和結(jié)束而建立和銷(xiāo)毀。
程序計(jì)數(shù)器
一塊較小的內(nèi)存空間,可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼行號(hào)指示器
Java虛擬機(jī)棧
Java虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型,每個(gè)方法在執(zhí)行的同時(shí)都會(huì)創(chuàng)建一個(gè)站幀(Stack Frame)用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。每個(gè)方法從調(diào)用到執(zhí)行完成的過(guò)程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中入棧到出棧的過(guò)程。
本地方法棧
本地方法棧與虛擬機(jī)棧發(fā)揮的作用類(lèi)似,虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則為虛擬機(jī)使用的Native方法服務(wù)。
Java堆
Java堆是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊。Java堆是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存。
Java堆是垃圾收集器管理的主要區(qū)域,因此很多時(shí)候也稱(chēng)作GC堆。
方法區(qū)
與Java堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域,它用于存儲(chǔ)已被虛擬機(jī)加載的類(lèi)信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。
執(zhí)行引擎
執(zhí)行通過(guò)類(lèi)加載器分配給運(yùn)行時(shí)數(shù)據(jù)區(qū)的字節(jié)碼,并將這些字節(jié)碼轉(zhuǎn)換成JVM虛擬機(jī)更容易執(zhí)行的語(yǔ)言。主要有三個(gè)子組件。
解釋器
負(fù)責(zé)讀取字節(jié)碼并順序的執(zhí)行。缺點(diǎn)是當(dāng)一個(gè)方法被多次調(diào)用時(shí),每次都需要新的解釋。
JIT(Just In Time)編譯器
抵消了解釋器執(zhí)行緩慢的缺點(diǎn)。JIT編譯器同時(shí)編譯字節(jié)碼的重復(fù)部分,總而減少編譯所需的總時(shí)間。從而提高性能。
- 中間代碼生成器 負(fù)責(zé)生成中間代碼
- 代碼優(yōu)化器 負(fù)責(zé)優(yōu)化上面生成的中間代碼
- 目標(biāo)代碼生成器 負(fù)責(zé)生成機(jī)器代碼或本機(jī)代碼
- Profiler 一個(gè)特殊組件,負(fù)責(zé)查找熱點(diǎn),即是否被多次調(diào)用
垃圾收集器
收集和刪除未引用的對(duì)象來(lái)釋放內(nèi)存??梢酝ㄟ^(guò)調(diào)用觸發(fā)垃圾收集System.gc(),但不保證執(zhí)行。
本地方法接口
JNI與本地方法庫(kù)交互,并提供執(zhí)行引擎所需的本地庫(kù)
本地方法庫(kù)
執(zhí)行引擎所需要的本地庫(kù)的集合