前言:每個(gè)Java開發(fā)人員都知道字節(jié)碼由JRE(Java運(yùn)行時(shí)環(huán)境)執(zhí)行。但許多人不知道JRE是Java Virtual Machine(JVM)的實(shí)現(xiàn),它分析字節(jié)碼,解釋代碼并執(zhí)行它税灌。作為開發(fā)人員吹害,我們應(yīng)該知道JVM的架構(gòu)是非常重要的螟凭,因?yàn)樗刮覀兡軌蚋行У鼐帉懘a。在本文中它呀,我們將更深入地了解Java中的JVM架構(gòu)和JVM的不同組件螺男。
什么是JVM?
Virtual Machine是物理機(jī)器的軟件實(shí)現(xiàn)纵穿。Java是用在VM上運(yùn)行的WORA(Write Once Run Anywhere)概念而開發(fā)的下隧。編譯器將Java文件編譯為Java .class文件,然后將.class文件輸入到JVM中谓媒,JVM會加載并執(zhí)行類文件淆院。下面是JVM的架構(gòu)圖。
JVM如何工作句惯?
如上面的架構(gòu)圖所示土辩,JVM分為三個(gè)主要子系統(tǒng):
類加載器子系統(tǒng)
運(yùn)行時(shí)數(shù)據(jù)區(qū)
執(zhí)行引擎
1.類加載器子系統(tǒng)
Java的動態(tài)類加載功能由類加載器子系統(tǒng)處理。它在運(yùn)行時(shí)抢野,而不是編譯時(shí)首次引用類的時(shí)候加載拷淘、鏈接、并初始化類文件指孤。
1.1加載
類將通過此組件加載启涯。Boot Strap Class Loader,Extension Class Loader和Application Class Loader是有助于實(shí)現(xiàn)的三個(gè)類加載器恃轩。
1.Boot Strap Class Loader——負(fù)責(zé)加載來自于Bootstrap類路徑的類结洼,就是rt.jar。此加載程序?qū)⒔o予最高優(yōu)先級详恼。
2.Extension Class Loader——負(fù)責(zé)加載在ext文件夾(jre lib)內(nèi)的類补君。
3.Application Class Loader——負(fù)責(zé)加載應(yīng)用程序級類路徑,路徑提到環(huán)境變量等
上面的類記載器在加載類文件時(shí)遵循Delegation Hierarchy 算法昧互。
1.2鏈接
1.驗(yàn)證——字節(jié)碼驗(yàn)證器將驗(yàn)證生成的字節(jié)碼是否正確挽铁,如果驗(yàn)證失敗伟桅,我們將得到verification error。
2.準(zhǔn)備——對于所有的靜態(tài)變量叽掘,內(nèi)存將被分配和配置默認(rèn)值楣铁。
3.解決——所有的符號存儲器引用都將替換為來自Method Area的原始引用。
1.3初始化
這是類加載的最后階段更扁,這里所有的靜態(tài)變量都將被賦予原始值盖腕,并執(zhí)行靜態(tài)塊。
2.運(yùn)行時(shí)數(shù)據(jù)區(qū)
運(yùn)行時(shí)數(shù)據(jù)區(qū)分為5個(gè)主要組件:
方法區(qū)——所有的類級別數(shù)據(jù)將存儲在這里浓镜,包括靜態(tài)變量溃列。每個(gè)JVM只有一個(gè)方法區(qū),并且它是一個(gè)共享資源膛薛。
堆區(qū)域——所有對象及其對應(yīng)的實(shí)例變量和數(shù)組將存儲在這里听隐。每個(gè)JVM也有一個(gè)堆區(qū)域。由于方法和堆區(qū)域共享多個(gè)線程的內(nèi)存哄啄,因此所存儲的數(shù)據(jù)非線程安全雅任。
堆棧區(qū)——對于每個(gè)線程,將創(chuàng)建一個(gè)單獨(dú)的運(yùn)行時(shí)棧咨跌。對于每個(gè)方法調(diào)用沪么,將在堆棧存儲器中產(chǎn)生一個(gè)條目,稱為堆棧幀锌半。所有局部變量將在堆棧內(nèi)存中創(chuàng)建禽车。堆棧區(qū)域是線程安全的,因?yàn)樗皇枪蚕碣Y源刊殉。堆棧幀分為三個(gè)子元素:
1.局部變量數(shù)組——與方法相關(guān)哭当,涉及局部變量以及將在此存儲的相應(yīng)值的多少。
2.操作數(shù)堆椚叱海——如果需要執(zhí)行任何中間操作,那么操作數(shù)堆棧將充當(dāng)運(yùn)行時(shí)工作空間來執(zhí)行操作陋葡。
3.幀數(shù)據(jù)——對應(yīng)于方法的所有符號存儲在此處亚亲。在任何異常的情況下,捕捉塊信息將被保持在幀數(shù)據(jù)中腐缤。
PC寄存器——每個(gè)線程都有單獨(dú)的PC寄存器捌归,用于保存當(dāng)前執(zhí)行指令的地址,一旦指令執(zhí)行岭粤,PC寄存器將更新到下一條指令惜索。
本地方法堆棧——本地方法堆棧保存本地方法信息。對于每個(gè)線程剃浇,將創(chuàng)建一個(gè)單獨(dú)的本地方法堆棧巾兆。
3.執(zhí)行引擎
分配給運(yùn)行時(shí)數(shù)據(jù)區(qū)的字節(jié)碼將由執(zhí)行引擎執(zhí)行猎物。執(zhí)行引擎讀取字節(jié)碼并逐個(gè)執(zhí)行它。
解釋器——解釋器解釋字節(jié)碼較快角塑,但執(zhí)行慢蔫磨。解釋器的缺點(diǎn)是當(dāng)一個(gè)方法被多次調(diào)用時(shí),每次都需要新的解析圃伶。
JIT編譯器——JIT編譯器消除了解釋器的缺點(diǎn)堤如。執(zhí)行引擎將在轉(zhuǎn)換字節(jié)碼時(shí)使用解釋器的幫助,但是當(dāng)它發(fā)現(xiàn)重復(fù)的代碼時(shí)窒朋,它使用JIT編譯器搀罢,編譯器會編譯整個(gè)字節(jié)碼并將其更改為本地代碼。這個(gè)本地代碼將直接用于重復(fù)的方法調(diào)用侥猩,從而提高系統(tǒng)性能榔至。
1.中間代碼生成器——生成中間代碼
2.代碼優(yōu)化器——負(fù)責(zé)優(yōu)化上面生成的中間代碼
3.目標(biāo)代碼生成器——負(fù)責(zé)生成機(jī)器代碼或本地代碼
4.分析器——一個(gè)特殊組件,負(fù)責(zé)查找熱點(diǎn)拭宁,即該方法是否被多次調(diào)用洛退。
垃圾收集器:收集和刪除未引用的對象〗鼙辏可以通過調(diào)用“System.gc()”觸發(fā)垃圾收集器兵怯,但不能保證執(zhí)行。JVM的垃圾回收收集創(chuàng)建的對象腔剂。
Java本機(jī)接口(JNI):JNI將與本地方法庫進(jìn)行交互媒区,并提供執(zhí)行引擎所需的本地庫。
本地方法庫:它是執(zhí)行引擎所需的本地庫的集合掸犬。
針對上面的技術(shù)我特意整理了一下袜漩,有很多技術(shù)不是靠幾句話能講清楚,所以干脆找朋友錄制了一些視頻湾碎,很多問題其實(shí)答案很簡單宙攻,但是背后的思考和邏輯不簡單,要做到知其然還要知其所以然介褥。如果想學(xué)習(xí)Java工程化座掘、高性能及分布式、深入淺出柔滔。微服務(wù)溢陪、Spring,MyBatis睛廊,Netty源碼分析的朋友可以加我的Java進(jìn)階群:694549689形真,群里有阿里大牛直播講解技術(shù),以及Java大型互聯(lián)網(wǎng)技術(shù)的視頻免費(fèi)分享給大家超全。
1.具有1-5工作經(jīng)驗(yàn)的咆霜,面對目前流行的技術(shù)不知從何下手邓馒,需要突破技術(shù)瓶頸的可以加群。
2.在公司待久了裕便,過得很安逸绒净,但跳槽時(shí)面試碰壁。需要在短時(shí)間內(nèi)進(jìn)修偿衰、跳槽拿高薪的可以加群挂疆。
3.如果沒有工作經(jīng)驗(yàn),但基礎(chǔ)非常扎實(shí)下翎,對java工作機(jī)制缤言,常用設(shè)計(jì)思想,常用java開發(fā)框架掌握熟練的可以加群视事。