引言
JVM(Java Virtual Machine)Java虛擬機的概念大家都不陌生,Java之所以可以做到“一次編譯,到處運行”的跨平臺性,其根本原因就在于JVM。JVM是建立在操作系統(OS)之上的,Java虛擬機屏蔽了開發人員與操作系統的直接接觸,我們在通過Java編寫程序時,只需要負責編寫Java代碼即可,關于具體的執行則會由JVM加載字節碼后翻譯成機械指令交給OS執行。
同時JVM方面的知識,在如今Java內卷日益加重的時代中,也變成了每位Java開發人員必須要掌握的一項技能,求職面試過程中,Java虛擬機也是面試官必問的話題。
一、初始Java虛擬機JVM
關于JVM是什么?在網上有很多官方而死板且難以讓人理解的介紹,在我看來,簡單的去理解它就是:一個架構在平臺上的平臺。這句話具體是什么意思呢?在Java之前,無論是C語言還是匯編等這類的底層語言開發出的程序,在不同的環境/系統下都需要進行不同編譯后才能執行的。而Java則反其道而行之,不再需要根據不同的環境而改變自己的代碼,而是自己架構出了一個平臺,開發人員編寫出的代碼只需要能夠在自己平臺上執行即可,完全屏蔽了開發者與操作系統的接觸,而這個Java自身架構出的平臺則被稱為JVM。同時,任何一門語言只要能夠轉換成class
文件,符合都能夠被JVM接受并執行。
舉個例子理解就是:類似于C、匯編這類的底層語言屬于“墻頭草”,代碼需要根據不同的環境進行改變。
而Java則因為JVM的原因則變成了“屋頂花”,無論環境怎么變,代碼都不需要跟著改變。
如下圖所示:
同時值得注意的一點是:JVM不僅僅能夠具備跨平臺性,也同樣存在跨語言性,只要別的語言寫出來的代碼最終轉換為JVM可識別讀取的
.class
文件,那么JVM也依舊可以執行它。
1.1、JDK、JRE與JVM之間的關系
而JVM是屬于JRE的,而在我們學習Java之初就曾學到:JDK、JRE與JVM幾個名詞,那么它們之間又是什么關系呢?
- JDK(Java Development Kit):Java的SDK開發工具包,包含工具包、JRE、JVM在內
- JRE(Java Runtime Environment):Java的運行時環境,包含JavaAPI、JVM在內,提供了Java程序執行的最低的環境要求
- JVM(Java Virtual Machine):Java自身架構的虛擬計算機平臺,是基于其他平臺基礎上進行架構的,為Java字節碼的執行提供了保障
從涵蓋度方面來說,JDK包含了JRE,JRE包含了JVM,而JVM則是作為Java程序執行的平臺。
1.2、虛擬機的兩種架構模型及JVM架構模型
目前虛擬機主要有兩種架構模型,一種是基于棧式的,另一種則是基于寄存器式的。從性能上說,基于寄存器模型會比基于棧式的虛擬機性能更好,但是從移植性上看,棧式的虛擬機會遠強于基于寄存器模型的虛擬機。
何謂基于棧式的虛擬機?
基于棧式指的是虛擬機在執行指令時,采用的方式是基于棧的指令集,會將需要執行的指令一條條的壓入棧中,主要有入棧和出棧兩種操作?;跅J降奶摂M機都會存在一個操作數棧的概念,虛擬機在真正運算時,都是通過操作數棧進行操作,與內存進行交互,簡單來說就是無論任何操作,都需要通過操作數棧進行。這種模型的虛擬機最大的好處在于可以無視硬件、物理架構。當然,缺點也非常明顯,因為無論什么操作都要經過操作數棧,所以性能會低一些。
Java的JVM、Python的CPython、.Net的CLR等虛擬機都是基于這種棧式模型的。
來簡單感受一下基于棧式的虛擬機運算過程:
/* ------Java代碼------ */
int a = 3;
int b = 2;
int c = a + b;
/* ------javap -c -v -p 查看到的字節碼------ */
0: iconst_3 // 將3放入操作數棧頂
1: istore_1 // 寫出操作數棧頂部元素,并將其放在局部變量表中索引為1的位置
2: iconst_2 // 將2放入操作數棧頂
3: istore_2 // 寫出操作數棧頂部元素,并將其放在局部變量表中索引為2的位置
4: iload_1 // 從局部變量表中加載索引位置=1的數據值
5: iload_2 // 從局部變量表中加載索引位置=2的數據值
6: iadd // 彈出操作棧頂的兩個元素并進行 加 操作(3 + 2)
7: istore_3 // 將加之后的結果刷寫到局部變量表中索引為3的位置
8: return // 返回
對于如上過程中,前四條分配指令就不分析了,重點分析一下后面的運算過程,也就是c=a+b
這個過程,具體執行如下:
- ①數據
a
從局部變量表經過總線傳輸到操作數棧 - ②數據
b
從局部變量表經過總線傳輸到操作數棧 - ③數據
a
從操作數棧經過總線傳輸給CPU
- ④數據
b
從操作數棧經過總線傳輸給CPU
- ⑤
CPU
計算完成后,將結果通過數據總線傳輸到操作數棧 - ⑥運算結果從操作數棧經過總線傳輸到
CPU
- ⑦
CPU
將數據經過總線傳輸到局部變量表賦值給c
從如上步驟可以看出,一次簡單的加法運算就需要經過七次總線傳輸,因為所有操作都要經過操作數棧的原因,所以效率方面會低許多。
什么又叫基于寄存器模型的虛擬機?
基于寄存器模型的虛擬機存在很多虛擬寄存器的概念,用于模擬CPU中真實的PC寄存器,但它們往往都是以別名存在,如:
R1、R2、R3....
等,在執行時,執行引擎需要對這些別名進行解析,然后找出具體操作數的位置,然后取出操作數進行操作。這些虛擬的寄存器也并不是直接在CPU中的,而是和操作數棧一樣,位于運行時棧中,通過一個數組(運行時棧幀中的連續內存空間)存儲所有的虛擬寄存器。
Android的Dalvik、Lua5.0的RegisterBased等虛擬機都是基于寄存器模型實現的。
還是和前面一樣,通過一個簡單的c=a+b
例子來理解這類基于寄存器模型的虛擬機運算過程:
// -------- Lua代碼 ----------
a = 2;
b = -1;
c = a + b;
// -------- 寄存器指令 --------
LW R1,a
LW R2,b
ADD R3,R1,R2
LW
是load
的意思,代表將數據a、b
加載到虛擬寄存器R1、R2
中。同樣的,重點分析一下運算的過程:
- ①數據
a
從R1
虛擬寄存器經總線傳輸到CPU
- ②數據
b
從R2
虛擬寄存器經總線傳輸到CPU
- ③
CPU
進行+
計算后將數據經總線刷寫回虛擬寄存器R3
中
從如上過程中不難看出,基于寄存器模型實現的虛擬機,虛擬寄存器中的數據在運算時,不需要先傳輸到操作數棧后再傳輸給總線運算,而是可以直接將數據送入物理CPU中。對比前面基于棧式的虛擬機,寄存器模型虛擬機明顯的會在性能方面更占優勢。因為在這種模型下的虛擬機是不存在操作數棧的概念,因此在運算時可以節省很多數據出/入棧(pop/push)的指令,也就代表中傳輸數據時會少很多的總線傳輸次數。
總的來說,基于棧式實現的虛擬機,因為要基于操作數棧進行操作,所以會有很多數據出棧/入棧的指令,指令數量會比寄存器模型下的虛擬機多出很多。而基于寄存器的指令是直接交給CPU在高速緩存區(L1/L2/L3)執行的,性能方面來說會更勝一籌。但因為基于寄存器的指令集是與硬件架構緊密關聯的,不同的CPU硬件架構下的指令會有些許不同,所以無法做到可移植。
Java的虛擬機JVM是基于棧式模型實現的,因為操作數棧的存在,所以不需要特別依賴于硬件支持,所以具備優異的跨平臺性。但“成也蕭何敗也蕭何”,因為所有操作都需要經過操作數棧再與內存交互的原因,所以執行效率并沒有那么高效,性能方面會有些慢。
但在目前的主流JVM中,都使用了JIT這類的即時編譯以及熱點探測技術,可以將一些經常運行的Java代碼直接轉化為機械碼(機械指令)保存,以后每次執行這些熱點代碼時并不會再通過字節碼方式運行,而是直接通過執行機械指令的方式操作。從而使得Java在具備跨平臺性的同時也能夠保證性能。
1.3、Java虛擬機的生命周期
JVM的生命周期一般會分為啟動、運行以及退出這三個階段:
- 啟動:
Bootstrap
加載器創建初始類,對JVM進行初始化并創建一個進程 - 運行:創建進程后的正常執行階段,平時所說的Java程序實際上就是一個JVM進程
- 退出:進程終止的階段,主要會分為如下幾種情況:
- ①程序正常執行結束退出
- ②執行過程中出現錯誤導致異常終止退出
- ③操作系統錯誤導致程序終止退出,如內存不足、系統崩潰等
- ④程序中使用代碼手動退出,如調用
System.exit
或Runtime.exit/halt
方法等 - ⑤JNI中加載或卸載虛擬機時退出
JVM的生命周期實際上與普通進程的生命周期一致,因為JVM對于操作系統而言,也僅是一個進程而已,JVM與其他程序的進程都會被“一視同仁”,不會有其他差異。
二、Java虛擬機的前世今生 - JVM發展史
每當談到JVM都會扯出很多話題,諸如JVM內存分區、GC分代/回收策略、JVM調優等等,而這些話題默認都是建立在HopSpot虛擬機上的,因為Oracle官網上下載的JDK中默認嵌入的虛擬機便是它。
但其實也可以自研JVM,只需符合Oracle官方給出的虛擬機的規范文檔即可,如國內外的一些大廠阿里、IBM、谷歌等,生產環境中應用的JVM都屬于自研的。
從Java語言的出現直至如今,曾經涌現和湮滅過許多經典的虛擬機,接下來讓我們來看看Java虛擬機家族的發展軌跡。
2.1、開創世紀 - Sun Classic VM
- 發布日期:1996年1月
- 研發出品:Sun公司
- 屬性:開創世紀(作為世界上第一款Java商用虛擬機發布)
這款虛擬機是無法混合解釋器和編譯器一起工作的,也代表著要么采用運行速度很慢的解釋器執行,要么采用編譯過程很長的編譯器運行。同時在這款虛擬機中,官方也僅提供了解釋器,如果要采用編譯器的話還需要額外獨自實現。
2.2、英雄氣短 - Sun Exact VM
- 發布日期:1998年12月
- 研發出品:Sun公司
- 屬性:英雄氣短(為后續的虛擬機打下了基礎,屬于承上啟下的角色)
這款虛擬機是Sun公司在JDK1.2中發布的,主要目的就是為了解決Sun Classic VM存在的各種隱患問題,同時這款虛擬機也是初步具備了現代高性能虛擬機中的雛形,其中首次實現了兩級即時編譯器、編譯器+解釋器混合工作模型兩種思想。Exact對比Classic來說,同時也采用了更加精準的內存管理方案-確切式內存管理方案,可以讓虛擬機知道內存中某個位置上的數據具體是何種類型,大大的提高GC回收效率。
不過比較有意思的是:這款虛擬機對比之前的ClassicVM,雖然技術上先進了很多,但是很快就被后面更加優秀的HotSpotVM代替掉了,真可謂是“英雄氣短”。
2.3、世界最快 - BEA JRockit VM
- 發布日期:2001年2月
- 研發出品:BEA公司
- 屬性:世界最快(專注于速度的虛擬機,可以將響應時間細化至毫秒/微妙級別)
這款虛擬機是BEA公司在2001年2月正式發布的,專注于服務端應用,不太關注程序的啟動速度,全部代碼會被編譯執行。同時它提供了全面的Java運行時解決方案:JRockit Real Time與MissionControl組件,前者可以將響應速度精確控制在毫秒、微妙級別,對于財政金融、軍事指揮、電信網絡等類型的項目擁有良好的支持,后者則屬于服務型組件,可以使用極底的資源開銷來管理、監控和分析生產環境中的Java程序。
2008年BEA公司被Oracle收購,JDK1.8中的HotSpot移植了JRockit的優秀特性。現在已經成炮灰了,湮滅在了歷史的長河之中。
2.4、武林霸主 - Sun HotSpot VM
- 發布日期:2000年5月
- 研發出品:Sun公司
- 屬性:虛擬機一哥(JDK默認、綜合性能最好、目前服務端應用最廣泛的虛擬機)
這款虛擬機最開始并不是由Sun公司研發的,而是由LongviewTechnologies的公司設計出的一款非應用于Java程序的虛擬機,1997年被Sun公司收購,整合了其優秀特性(JIT即時編譯、熱點代碼探測等),最終得到了HotSpotVM。這款虛擬機最大的特點是可以通過執行計數器,在Java程序運行過程中找出最具有編譯價值的代碼(執行次數夠多的代碼),然后通知JIT編譯器進行編譯,通過編譯器和解釋器的一同合作,在程序響應時間和執行性能中取得最佳的平衡點,這樣即避免了JRockit的編譯時間過長問題,也解決了Classic這類虛擬機執行效率過慢問題。
這款虛擬機是服務器應用最廣泛,并且也是最為特殊的虛擬機。因為Oracle在2008和2009兩年,分別收購了BEA和Sun公司,得到了兩款優秀的Java虛擬機:JRockit 和HotSpot,而Oracle將這兩款虛擬機的優勢進行移植整合,打造出了更加優秀的HotSpot VM,也就是JDK1.8中內嵌的虛擬機,或許我們將它稱為“HotRockit”會更加合適。
2.5、獨樹一幟 - IBM J9 VM
- 發布日期:2017年9月
- 研發出品:IBM公司
- 屬性:獨樹一幟(IBM相關軟件、硬件、平臺捆綁發布的虛擬機)
IBM J9 VM的市場定位與HotSpot差不多,但J9是一款設計上從服務器到桌面程序再到嵌入式全面考慮的多用途虛擬機。但因為與Oracle有協議,IBM不允許私自發布單獨的J9虛擬機,所以一般應用J9虛擬機的多是IBM自己的產品或平臺,如IBM的WebSphere產品、AIX/Z操作系統上部署的Java程序等。所以一般J9是作為IBM內部應用的虛擬機使用的,但在2017年9月開源貢獻給了Ecalipse基金會,命名為OpenJ9。
2.6、性能魔獸 - Azul Zing VM
- 發布日期:2010年
- 研發出品:Azul Systems公司
- 屬性:性能魔獸(可管理上TB級別堆內存、低延遲高吞吐、GC最流暢的虛擬機)
Azul Zing VM是之前Sun還未被收購時,從HotSpot虛擬機上fork的一個分支,但經過多年的內部自研,修改了虛擬機內的許多細節實現,同時也為它重新寫了一套GC,支持幾TB量級的堆空間管理。同時也配套了ZVision/ZVRobot這類的性能監控工具,可以方便用戶監控JVM的運行狀態,比如鎖狀態競爭、對象分配過程、熱點代碼探測等細節方面都能進行監控。
總的來說,Zing擁有高吞吐低延遲、快速預熱、易于監控的特性,但很遺憾的是:它收費,并且價錢不菲。不過它也有一個開源版本:Zulu VM。
2.7、腹死胎中 - Apache Harmony VM
- 研發出品:Apache基金會
- 屬性:腹死胎中(Java史上最慘的虛擬機)
這款虛擬機比較有意思,本身背景也比較強,典型的JVM家族中的“富二代”,IBM和Intel聯手開源的JVM,背后有世界兩大頂級大廠支持。本身是有望成為F/OSS系的主流虛擬機的,可無奈被Sun公司坑了一把,最終腹死胎中。
Harmony是Java的開源實現,但由于許可上的糾紛,Harmony項目永遠不可能自稱為Java虛擬機或是Java核心語言庫的實現。Harmony項目也一直在努力爭取獲得JCP(Java Community Process)的JCK授權。但是,由于Sun公司的態度,JCP僅僅允許授權給Harmony一個帶有限制條件的TCK,即僅僅能使用在J2SE,而不是所有Java實現上(包括J2ME和J2EE)。兩者之間自始發生沖突。當Oracle掌權Java后,這一沖突繼續延續。最終Sun公司陰的這手,硬活生生的把擁有“美好前程”的Harmony拖死了。
這事還有后續,在2010年12月,Apache基金會不滿JCP組織的處理,直接宣布退出了JCP組織。
2.8、別出心裁 - Kilobyte VM與CDC/CLDC HotSpot VM
Kilobyte VM簡稱KVM,CDC/CLDC則是HotSpot對標它,針對JavaME這一產品線的版本。這兩虛擬機與其他虛擬機不同,之前的虛擬機都是建立在OS的基礎上架構出一個可執行平臺,而KVM則是屬于內核虛擬機,虛擬機可直接連接/操控鍵盤來執行程序。主要應用與智能控制器、傳感器、老人/按鍵手機等產品上。
2.9、百家爭鳴 - 其他虛擬機
在Java的高速發展期階段(1990-2008年左右)實現各自的虛擬機的企業,簡直可謂是百家爭鳴。期間驚鴻一現過許多優秀的虛擬機,但當Orcale收購掉Sun和BEA公司后,Java虛擬機的百家爭鳴期結束,最終由Orcale整合了HotSpot、JRockit優良基因的“HotRockit”版HotSpot登上了霸主地位。
直至如今,可選擇的虛擬機類型并不算多了,但到目前還能存活下來的虛擬機都有各自的優勢。下面再給出一些涌現過的虛擬機(不一定全部被淘汰了,有些目前還在使用):
- TaoBao VM:淘寶基于HotSpot開發的定制版超高性能虛擬機
- Dalvik VM:谷歌開發的虛擬機,用于安卓系統,沒有遵循Java虛擬機規范開發的
- 應用于Android 5.0之前,編譯后生成的是dex文件,基于寄存器模型實現
- Android 5.0之后谷歌推出了一款新的虛擬機,ART VM代替它
- Lemur VM:阿里云開發的可以同時兼容Android與Java應用的虛擬機
- Squawk VM:Sun公司之前專門為小型嵌入式環境開發的虛擬機
- Liquid VM:BEA公司開發的一款直接操控硬件的VM,可以避免用戶態到內核態的切換
- Microsoft VM:微軟當時為了在IE3中支持Java應用的運行而開發的虛擬機
- Jikes RVM:IBM開發出的專門用于研究JVM的元循環虛擬機(學術版:用于研究)
- Maxine VM:Oracle和原Sun公司成員研發出的元循環虛擬機,也是同樣的作用
- Grall VM:Oracle最新開源的全??缙脚_虛擬機,可以任何語言的執行平臺使用
- ........
在上面我們提到過一個概念:元循環虛擬機,這是什么意思?元循環虛擬機指的是用語言本身寫虛擬機,也就是用Java開發出的JVM。
ok~,JVM家族的發展史至此就暫且打住了,相對來說,目前在J2EE領域占絕對地位的肯定是HotSpot,而在J2ME領域的龍頭必然是J9,無可厚非。
其實從Oracle最新發布的Grall虛擬機來說,未來的虛擬機的奮斗方向肯定是朝著更加精確的模塊化、更強的GC機制、混合多語言執行以及多核并行執行的目標不斷前進的。
三、Java虛擬機之JVM組成架構
Java虛擬機一般是由多個模塊一起組成的,主要可分為類加載子系統、執行引擎子系統、運行時數據區、垃圾回收子系統以及本地接口和本地方法庫。在Java程序啟動/執行過程中,這些模塊各司其職,相互配合,組成了整個Java的執行平臺 - JVM。
列出來的這些是從整體上涵蓋了整個JVM進行劃分的,而并不是從某個維度上進行劃分,本篇中先對于這些進行簡單介紹,后續文章中再依次進行深入分析。
3.1、類加載子系統
類加載子系統是用于加載編譯后class
文件的,但它只負責將符合格式要求的class
字節碼信息加載進內存,而只要符合格式規范的class
文件都能被加載,至于加載進入的class
文件到底是否能執行就并不是它負責的了,這是執行引擎子系統的范圍之內的責任。
而類加載子系統中,核心知識點分為類加載器、雙親委派模型、類加載過程三大塊。
3.2、執行引擎子系統
執行引擎子系統擔任著JVM的“翻譯官”角色,它負責將加載進內存的class
字節碼指令“翻譯”成機器語言交由硬件執行。而字節碼可以通過解釋器和即使編譯器兩種途徑轉換為機械指令。HotSpot
虛擬機中,采用的便是解釋器+即使編譯器混合執行的工作模式。
3.3、運行時數據區
運行時數據區是整個JVM中的重點,開發者編寫的所有代碼最終都會被加載在這里之后再開始執行。同時,Java為何能夠避免像C那樣,需要手動管理內存的原因之一也在于這塊區域。
同時這也是整個JVM“黑盒”中,開發者能夠接觸到的為數不多的區域。
Java運行時數據區主要可分為PC程序計數器、本地方法棧、虛擬機棧、元數據空間(方法區)以及堆空間五大區域,這也是后續分析時的核心內容。但Java虛擬機規范對它的定義是是比較抽象的,運行時數據結構上的細節方面在JVM規范中并沒有明確指出,大多數都是由JVM具體的實現廠商自行決定。
3.4、垃圾回收子系統
垃圾回收子系統在Java虛擬機規范中,其實沒有明確規定必須要實現,但在沒有發明無限的內存硬件之前,絕大部分的JVM實現時,都是有垃圾回收模塊的。GC模塊的主要任務就是幫助Java程序管理內存,對于垃圾對象的清楚、存活對象的管理以及內存碎片的回收等工作,都交由GC系統負責。
同時Java能夠做到避免像C那樣需手動管理內存的最終原因也得益于GC機制,GC機制自動幫開發者管理了內存,從而屏蔽了開發人員和內存的直接接觸。
JVM的GC機制里面重點知識點分為三塊:垃圾回收器、垃圾回收算法、GC調優。
3.5、本地接口和本地方法庫
本地方法接口的作用主要是為了融合不同的編程語言為Java所用,它的初衷是融合C/C++程序。因為在Java誕生時,正是C語言橫行的時候,要想立足就必須要有一個能夠調用C代碼的模塊,于是就專門在內存中開辟了一塊區域處理標記為native的方法。它在執行時,而本地方法接口的作用則是將本地方法棧中登記的被調用的本地方法,在執行引擎處理時,將C編寫的native方法從本地方法庫中加載出來。
簡而言之,本地方法接口就是一個Java調用非Java代碼的接口,這個非Java代碼一般泛指C語言所編寫的本地方法庫中的函數。
OK~,至此簡單的分析了一下JVM的架構組成,先讓大家對JVM的整體有個了解。
JVM是一個架構在平臺上的平臺,其中被分為了不同的模塊,虛擬機在運行過程中則是通過這些模塊相互配合,從而做到了執行Java代碼。不過值得注意一提的是:JVM的知識點雖然比較多,但開發過程中,能夠被開發者直接接觸的區域卻是少之又少,往往所謂的JVM調優,也僅僅只是對于GC和運行時數據區進行優化。當然,也包括JVM的配置優化,根據不同的機器、項目,在啟動時,指定對應參數開啟最佳的配置。
四、HotSpot虛擬機源碼
因為目前大部分部署的Java程序都是默認使用HotSpot虛擬機,所以后續的文章中大部分的內容也會建立在HotSpot虛擬機的基礎上進行分析。如果有效果對于它的源碼比較感興趣,也可以去Oracle官網下載,但官網上下載時會經常連接中斷,所以附上網盤資源鏈接/提取碼:m3gm(注:下載的是Open-JDK1.8的源碼)。同時再源碼目錄結構,如下:
├─agent Serviceability Agent的客戶端實現
├─make 用來build出HotSpot的各種配置文件
├─src HotSpot VM的源代碼
│ ├─cpu CPU相關代碼(匯編器、模板解釋器、ad文件、部分runtime函數在這里實現)
│ ├─os 操作系相關代碼
│ ├─os_cpu 操作系統+CPU的組合相關的代碼
│ └─share 平臺無關的共通代碼
│ ├─tools 工具
│ │ ├─hsdis 反匯編插件
│ │ ├─IdealGraphVisualizer 將server編譯器的中間代碼可視化的工具
│ │ ├─launcher 啟動程序“java”
│ │ ├─LogCompilation 將-XX:+LogCompilation輸出的日志(hotspot.log)整理成更容易閱讀的格式的工具
│ │ └─ProjectCreator 生成Visual Studio的project文件的工具
│ └─vm HotSpot VM的核心代碼
│ ├─adlc 平臺描述文件(上面的cpu或os_cpu里的*.ad文件)的編譯器
│ ├─asm 匯編器接口
│ ├─c1 client編譯器(又稱“C1”)
│ ├─ci 動態編譯器的公共服務/從動態編譯器到VM的接口
│ ├─classfile 類文件的處理(包括類加載和系統符號表等)
│ ├─code 動態生成的代碼的管理
│ ├─compiler 從VM調用動態編譯器的接口
│ ├─gc_implementation GC的實現
│ │ ├─concurrentMarkSweep Concurrent Mark Sweep GC的實現
│ │ ├─g1 Garbage-First GC的實現(不使用老的分代式GC回收器)
│ │ ├─parallelScavenge ParallelScavenge GC的實現(server VM默認,不使用老的分代式GC框架)
│ │ ├─parNew ParNew GC的實現
│ │ └─shared GC的共通實現
│ ├─gc_interface GC的接口
│ ├─interpreter 解釋器,包括“模板解釋器”(官方版在用)和“C++解釋器”(官方版不在用)
│ ├─libadt 一些抽象數據結構
│ ├─memory 內存管理相關(老的分代式GC框架也在這里)
│ ├─oops HotSpot VM的對象系統的實現
│ ├─opto server編譯器(又稱“C2”或“Opto”)
│ ├─prims HotSpot VM的對外接口,包括部分標準庫的native部分和JVMTI實現
│ ├─runtime 運行時支持庫(包括線程管理、編譯器調度、鎖、反射等)
│ ├─services 主要是用來支持JMX之類的管理功能的接口
│ ├─shark 基于LLVM的JIT編譯器(官方版里沒有使用)
│ └─utilities 一些基本的工具類
└─test 單元測試
如上便是HotSpot源碼中各個目錄的具體含義。
五、總結
本章簡單的概述了一下JVM的大體構成,并沒有對每個細節點進入深入分析,本章的宗旨在于:先簡單認識JVM,后續的文章中會繼續深入分析。