原文
JVM架構(gòu)圖分析
下圖:參考網(wǎng)絡(luò)+書籍,如有侵權(quán)請(qǐng)見諒?(想了解Hadoop內(nèi)存溢出請(qǐng)看:?Hadoop內(nèi)存溢出(OOM)分類、參數(shù)調(diào)優(yōu)化)
JVM被分為三個(gè)主要的子系統(tǒng)
(1)類加載器子系統(tǒng)(2)運(yùn)行時(shí)數(shù)據(jù)區(qū)(3)執(zhí)行引擎
1. 類加載器子系統(tǒng)
Java的動(dòng)態(tài)類加載功能是由類加載器子系統(tǒng)處理。當(dāng)它在運(yùn)行時(shí)(不是編譯時(shí))首次引用一個(gè)類時(shí),它加載、鏈接并初始化該類文件。
1.1?加載
類由此組件加載。啟動(dòng)類加載器?(BootStrap class Loader)、擴(kuò)展類加載器(Extension class Loader)和應(yīng)用程序類加載器(Application class Loader)?這三種類加載器幫助完成類的加載。
1.? 啟動(dòng)類加載器?–?負(fù)責(zé)從啟動(dòng)類路徑中加載類,無非就是rt.jar。這個(gè)加載器會(huì)被賦予最高優(yōu)先級(jí)。
2.? 擴(kuò)展類加載器?–?負(fù)責(zé)加載ext?目錄(jre\lib)內(nèi)的類.
3.? 應(yīng)用程序類加載器?–?負(fù)責(zé)加載應(yīng)用程序級(jí)別類路徑,涉及到路徑的環(huán)境變量等etc.
上述的類加載器會(huì)遵循委托層次算法(Delegation Hierarchy Algorithm)加載類文件。
1.2?鏈接
1.? 校驗(yàn)?– 字節(jié)碼校驗(yàn)器會(huì)校驗(yàn)生成的字節(jié)碼是否正確,如果校驗(yàn)失敗,我們會(huì)得到校驗(yàn)錯(cuò)誤。
2.? 準(zhǔn)備?–?分配內(nèi)存并初始化默認(rèn)值給所有的靜態(tài)變量。
3.? 解析?–?所有符號(hào)內(nèi)存引用被方法區(qū)(Method Area)的原始引用所替代。
1.3?初始化
這是類加載的最后階段,這里所有的靜態(tài)變量會(huì)被賦初始值,?并且靜態(tài)塊將被執(zhí)行。
2.?運(yùn)行時(shí)數(shù)據(jù)區(qū)(Runtime Data Area)
The 運(yùn)行時(shí)數(shù)據(jù)區(qū)域被劃分為5個(gè)主要組件:
2.1 方法區(qū)(Method Area)
所有類級(jí)別數(shù)據(jù)將被存儲(chǔ)在這里,包括靜態(tài)變量。每個(gè)JVM只有一個(gè)方法區(qū),它是一個(gè)共享的資源。
2.2 堆區(qū)(Heap Area)
所有的對(duì)象和它們相應(yīng)的實(shí)例變量以及數(shù)組將被存儲(chǔ)在這里。每個(gè)JVM同樣只有一個(gè)堆區(qū)。由于方法區(qū)和堆區(qū)的內(nèi)存由多個(gè)線程共享,所以存儲(chǔ)的數(shù)據(jù)不是線程安全的。
2.3 棧區(qū)(Stack Area)
對(duì)每個(gè)線程會(huì)單獨(dú)創(chuàng)建一個(gè)運(yùn)行時(shí)棧。對(duì)每個(gè)函數(shù)呼叫會(huì)在棧內(nèi)存生成一個(gè)棧幀(Stack Frame)。所有的局部變量將在棧內(nèi)存中創(chuàng)建。棧區(qū)是線程安全的,因?yàn)樗皇且粋€(gè)共享資源。棧幀被分為三個(gè)子實(shí)體:
a 局部變量數(shù)組?–?包含多少個(gè)與方法相關(guān)的局部變量并且相應(yīng)的值將被存儲(chǔ)在這里。
b 操作數(shù)棧?–?如果需要執(zhí)行任何中間操作,操作數(shù)棧作為運(yùn)行時(shí)工作區(qū)去執(zhí)行指令。
c 幀數(shù)據(jù)?– 方法的所有符號(hào)都保存在這里。在任意異常的情況下,catch塊的信息將會(huì)被保存在幀數(shù)據(jù)里面。
2.4 PC寄存器
每個(gè)線程都有一個(gè)單獨(dú)的PC寄存器來保存當(dāng)前執(zhí)行指令的地址,一旦該指令被執(zhí)行,pc寄存器會(huì)被更新至下條指令的地址。
2.5 本地方法棧
本地方法棧保存本地方法信息。對(duì)每一個(gè)線程,將創(chuàng)建一個(gè)單獨(dú)的本地方法棧。
3. 執(zhí)行引擎
分配給運(yùn)行時(shí)數(shù)據(jù)區(qū)的字節(jié)碼將由執(zhí)行引擎執(zhí)行。執(zhí)行引擎讀取字節(jié)碼并逐段執(zhí)行。
3.1? 解釋器:
?解釋器能快速的解釋字節(jié)碼,但執(zhí)行卻很慢。 解釋器的缺點(diǎn)就是,當(dāng)一個(gè)方法被調(diào)用多次,每次都需要重新解釋。
編譯器
JIT編譯器消除了解釋器的缺點(diǎn)。執(zhí)行引擎利用解釋器轉(zhuǎn)換字節(jié)碼,但如果是重復(fù)的代碼則使用JIT編譯器將全部字節(jié)碼編譯成本機(jī)代碼。本機(jī)代碼將直接用于重復(fù)的方法調(diào)用,這提高了系統(tǒng)的性能。
a.?中間代碼生成器?– 生成中間代碼
b.?代碼優(yōu)化器?– 負(fù)責(zé)優(yōu)化上面生成的中間代碼
c.?目標(biāo)代碼生成器?– 負(fù)責(zé)生成機(jī)器代碼或本機(jī)代碼
d.? 探測(cè)器(Profiler)?– 一個(gè)特殊的組件,負(fù)責(zé)尋找被多次調(diào)用的方法。
3.3? 垃圾回收器:
收集并刪除未引用的對(duì)象??梢酝ㄟ^調(diào)用"System.gc()"來觸發(fā)垃圾回收,但并不保證會(huì)確實(shí)進(jìn)行垃圾回收。JVM的垃圾回收只收集哪些由new關(guān)鍵字創(chuàng)建的對(duì)象。所以,如果不是用new創(chuàng)建的對(duì)象,你可以使用finalize函數(shù)來執(zhí)行清理。
Java本地接口 (JNI):?JNI?會(huì)與本地方法庫(kù)進(jìn)行交互并提供執(zhí)行引擎所需的本地庫(kù)。
本地方法庫(kù):它是一個(gè)執(zhí)行引擎所需的本地庫(kù)的集合。
JVM三大核心區(qū)域

