JVM 體系結(jié)構(gòu)詳解
JVM 是一種抽象的計(jì)算機(jī),基于堆棧架構(gòu),它有自己的指令集和內(nèi)存管理,是 Java 跨平臺(tái)的依據(jù),JVM解釋執(zhí)行字節(jié)碼,或?qū)⒆止?jié)碼編譯成本地代碼執(zhí)行。Java 虛擬機(jī)體系結(jié)構(gòu)如下:
Class File
Class File 是平臺(tái)無(wú)關(guān)的二進(jìn)制文件,包含著能被JVM執(zhí)行的字節(jié)碼,其中多字節(jié)采用大端序,字符使用一種改進(jìn)的UTF-8編碼。Class文件精確的描述了一個(gè)類或接口的信息,其中包括:
- 常量池:數(shù)值和字符串字面常量,元數(shù)據(jù)如類名、方法名稱、參數(shù),以及各種符號(hào)引用
- 方法的字節(jié)碼指令,參數(shù)個(gè)數(shù),局部變量,最大操作數(shù)棧深度,異常等信息
Class Loader
類加載器,JVM在類首次使用時(shí)動(dòng)態(tài)的加載、鏈接和初始化。JVM默認(rèn)的加載模型是雙親委派模型,類加載器之間存在父子關(guān)系的層次結(jié)構(gòu),內(nèi)部使用組合實(shí)現(xiàn)。此外還有其他的加載方式,比如Servlet加載,它先嘗試自己加載,不成功再委派上層加載器,類隔離;OSGI加載器之間是一種網(wǎng)狀的依賴關(guān)系,沒(méi)有上下層的區(qū)分,比較靈活。
加載
加載就是將Class文件表示的類或接口,在JVM方法區(qū)中創(chuàng)建一個(gè)與之對(duì)應(yīng)的java.lang.Class對(duì)象,像Class.forName()、ClassLoader.loadClass()、反射都能觸發(fā)類加載。當(dāng)觸發(fā)一個(gè)類加載時(shí),詳細(xì)的過(guò)程如下:
- 檢查類是否已經(jīng)被加載
- 將加載請(qǐng)求委派給上層類加載器
- 自己嘗試搜索類并加載
當(dāng)ClassLoader在classpath中未找到類文件,會(huì)拋出ClassNotFoundException;當(dāng)類A引用類B,類A已經(jīng)成功加載,但是加載B時(shí)未找到類文件,會(huì)拋出NoClassDefFoundError。JVM有以下幾種類加載器:
- Bootstrap ClassLoader,啟動(dòng)類加載器,加載 <java_home>\jre\lib 中 Java 核心類庫(kù)
- Extension ClassLoader,擴(kuò)展類加載器,加載 <java_home>\jre\lib\ext 中的類
- System ClassLoader,系統(tǒng)類加載器,也叫應(yīng)用程序類加載器(Application class loader),加載 CLASSPATH 環(huán)境變量中的類
鏈接
- 驗(yàn)證:確保class文件的正確性。
- 準(zhǔn)備:為類靜態(tài)字段分配內(nèi)存并初始化為默認(rèn)值,不會(huì)執(zhí)行任何字節(jié)碼指令。
- 解析:將符號(hào)引用轉(zhuǎn)為方法區(qū)(運(yùn)行時(shí)常量池)直接引用
初始化
執(zhí)行類初始化方法,即賦值靜態(tài)字段,執(zhí)行靜態(tài)塊,順序按照其定義的先后。父類的靜態(tài)域會(huì)先于子類靜態(tài)域初始化。
至此,一個(gè)類或接口被加載到了內(nèi)存中,JVM會(huì)保證整個(gè)過(guò)程是線程安全的。需要注意的是整個(gè)過(guò)程沒(méi)有涉及到任何實(shí)例對(duì)象。
運(yùn)行時(shí)數(shù)據(jù)區(qū)
1. Method Area:線程共享,存儲(chǔ)運(yùn)行時(shí)常量池、類字段和方法信息、靜態(tài)變量和方法的字節(jié)碼,是堆的邏輯組成部分,這部分的垃圾回收是可選的。值得一提的是Hotspot JVM自JDK8之后,調(diào)整了這部分內(nèi)存的內(nèi)容,class meta-data的分配使用本地內(nèi)存,interned String和類靜態(tài)變量移動(dòng)到了Java堆。
2. 運(yùn)行時(shí)常量池:對(duì)于JVM來(lái)說(shuō)具有核心作用,基本上涉及到方法或字段,JVM就會(huì)在運(yùn)行時(shí)常量池中搜索其具體的內(nèi)存地址。
3. Heap:線程共享,存儲(chǔ)實(shí)例對(duì)象,實(shí)例變量以及數(shù)組,是垃圾回收的主要區(qū)域。
4. JVM Stack:線程私有,用于存儲(chǔ)棧幀,當(dāng)方法被調(diào)用時(shí)會(huì)創(chuàng)建一個(gè)棧幀入棧,棧幀由以下幾部分組成:
- 局部變量表:從0開(kāi)始存儲(chǔ)this、方法參數(shù)、局部變量。
- 操作數(shù)棧:方法的工作區(qū),在操作數(shù)棧和局部變量之間交換數(shù)據(jù),存儲(chǔ)中間結(jié)果,操作數(shù)棧深度在編譯時(shí)就能確定。
- 幀數(shù)據(jù):方法返回值,異常分派,以及當(dāng)前方法所在類運(yùn)行時(shí)常量池的引用。
5. PC Register:線程私有,保存當(dāng)前指令地址,執(zhí)行后指向下一條指令地址。
6. Native Method Stack:線程私有,存儲(chǔ)本地方法信息,C或C++棧。
執(zhí)行引擎
讀取、翻譯、執(zhí)行字節(jié)碼。JVM基于棧架構(gòu),這個(gè)棧就是操作數(shù)棧,字節(jié)碼指令就是通過(guò)它進(jìn)行各種運(yùn)算。此外還有基于寄存器的虛擬機(jī)。
- Interpreter,翻譯:解釋字節(jié)碼比較快,執(zhí)行慢,缺點(diǎn)是每次方法調(diào)用都要重新翻譯解釋一遍。
- JIT Compiler,即時(shí)編譯:找出程序中頻繁調(diào)用的熱點(diǎn)方法,將字節(jié)碼編譯成本地代碼,提高性能。
- Garbage Collector,垃圾收集器:回收無(wú)效對(duì)象,判斷對(duì)象是否可回收,可采用不同的垃圾回收算法。
本地方法接口和庫(kù)
JNI,調(diào)用本地方法,c/c++庫(kù);執(zhí)行引擎所需的本地方法庫(kù)。
小結(jié)
主流JVM的實(shí)現(xiàn)有Oracle的Hotspot JVM、JRockit以及IBM的JVM。說(shuō)到JVM調(diào)優(yōu),默認(rèn)指的就是Hotspot VM,足見(jiàn)其流行程度。如今搞Java不去了解JVM就顯得有點(diǎn)low了-v-。
要想寫(xiě)出高質(zhì)量代碼,不僅要了解JVM,像調(diào)優(yōu),問(wèn)題排查等都需要完備的計(jì)算機(jī)基礎(chǔ)知識(shí),其實(shí)無(wú)論用什么語(yǔ)言開(kāi)發(fā),都是一個(gè)構(gòu)建和完善自身計(jì)算機(jī)知識(shí)體系的過(guò)程。
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!
相關(guān)文章
關(guān)于spring中事務(wù)的傳播機(jī)制
這篇文章主要介紹了關(guān)于spring中事務(wù)的傳播機(jī)制,所謂事務(wù)傳播機(jī)制,也就是在事務(wù)在多個(gè)方法的調(diào)用中是如何傳遞的,是重新創(chuàng)建事務(wù)還是使用父方法的事務(wù),需要的朋友可以參考下2023-05-05Springcloud中的Nacos?Config服務(wù)配置流程分析
這篇文章主要介紹了Springcloud中的Nacos?Config服務(wù)配置,本文以用戶微服務(wù)為例,進(jìn)行統(tǒng)一的配置,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09springboot用戶數(shù)據(jù)修改的詳細(xì)實(shí)現(xiàn)
用戶管理功能作為所有的系統(tǒng)是必不可少的一部分,下面這篇文章主要給大家介紹了關(guān)于springboot用戶數(shù)據(jù)修改的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04SpringCloud?集成Sentinel的實(shí)戰(zhàn)教程
這篇文章主要介紹了SpringCloud?集成Sentinel的詳細(xì)過(guò)程,本文通過(guò)實(shí)例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2024-08-08面試總結(jié):秒殺設(shè)計(jì)、AQS 、synchronized相關(guān)問(wèn)題
Java語(yǔ)言的關(guān)鍵字,當(dāng)它用來(lái)修飾一個(gè)方法或者一個(gè)代碼塊的時(shí)候,能夠保證在同一時(shí)刻最多只有一個(gè)線程執(zhí)行該段代碼。本文給大家介紹java中 synchronized的用法,對(duì)本文感興趣的朋友一起看看吧2021-06-06Springboot @Value獲取值為空問(wèn)題解決方案
這篇文章主要介紹了Springboot @Value獲取值為空問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02Java面試突擊為什么要用HTTPS及它的優(yōu)點(diǎn)
這篇文章主要介紹了Java面試突擊為什么要用HTTPS及它的優(yōu)點(diǎn),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-07-07Java+Selenium實(shí)現(xiàn)文件上傳下載功能詳解
這篇文章主要介紹了java代碼如何利用selenium操作瀏覽器上傳和下載文件功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2023-01-01SpringMVC中DispatcherServlet的HandlerMapping詳解
這篇文章主要介紹了SpringMVC中DispatcherServlet的HandlerMapping詳解,上回說(shuō)的Handler,我們說(shuō)是處理特定請(qǐng)求的,也就是說(shuō),不是所有的請(qǐng)求都能處理,那么問(wèn)題來(lái)了,我們?cè)踔滥膫€(gè)請(qǐng)求是由哪個(gè)Handler處理的呢,需要的朋友可以參考下2023-10-10