溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java虛擬機(jī)經(jīng)典問題有哪些

發(fā)布時(shí)間:2022-01-04 16:39:07 來源:億速云 閱讀:144 作者:iii 欄目:編程語言

本篇內(nèi)容介紹了“Java虛擬機(jī)經(jīng)典問題有哪些”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

Java 是如何在保證可移植性的前提下提供高執(zhí)行效率的?

Java虛擬機(jī)經(jīng)典問題有哪些

Java 程序最為常見的執(zhí)行方式,是預(yù)先編譯為一種名為 Java 字節(jié)碼的中間代碼格式。這種代碼格式無法直接運(yùn)行在 CPU 之上,而是需要借助 JVM 來執(zhí)行。換句話說,只要某個(gè)平臺(tái)提供了合乎 JVM 規(guī)范的實(shí)現(xiàn),它便能執(zhí)行這份 Java 字節(jié)碼。這也就是我們經(jīng)常說的“一次編寫,到處運(yùn)行”。

主流的 OpenJDK/OracleJDK 中所提供的 JVM 叫做 HotSpot。它同時(shí)采用了解釋執(zhí)行和即時(shí)編譯。解釋執(zhí)行就好比同聲傳譯,JVM 一邊理解輸入的字節(jié)碼一邊向 CPU 發(fā)出指令序列;即時(shí)編譯則是“磨刀不誤砍柴工”,JVM 會(huì)在運(yùn)行過程中將熱點(diǎn)代碼編譯成為可直接執(zhí)行的二進(jìn)制代碼。

這種混合執(zhí)行模式是建立在程序符合二八定律的假設(shè)上,即百分之二十的代碼占據(jù)了百分之八十的計(jì)算資源。對(duì)于不常用代碼,我們無需耗費(fèi)時(shí)間將其編譯成二進(jìn)制代碼,而是采取解釋執(zhí)行的方式運(yùn)行;另一方面,對(duì)于僅占據(jù)小部分的熱點(diǎn)代碼,JVM 則會(huì)花費(fèi)時(shí)間將其編譯為二進(jìn)制代碼,以達(dá)到理想的運(yùn)行效率。

異常捕獲是如何實(shí)現(xiàn)的?

Java虛擬機(jī)經(jīng)典問題有哪些

在編譯生成的 Java 字節(jié)碼中,每個(gè)方法都附帶一個(gè)異常表。異常表中的每一行均定義了一條異常執(zhí)行路徑,其中包括規(guī)定捕獲范圍的起始字節(jié)碼索引、終止(不包含)字節(jié)碼索引,異常處理代碼的起始字節(jié)碼索引,以及所捕獲的異常類型。

當(dāng)程序觸發(fā)異常時(shí),JVM 會(huì)從上至下遍歷異常表中的所有條目。當(dāng)觸發(fā)異常的字節(jié)碼的索引值在某行異常表?xiàng)l目的捕獲范圍內(nèi),JVM 會(huì)判斷所拋出的異常和該條目想要捕獲的異常是否匹配。如果匹配,JVM 會(huì)將控制流轉(zhuǎn)移至該條目所指向的異常處理代碼。

上述異常捕獲機(jī)制還被用于 finally 從句的實(shí)現(xiàn)。通常,Java 程序的編譯器 javac 會(huì)復(fù)制多份 finally 代碼塊,放置于生成的 Java 字節(jié)碼之中,然后通過生成多行異常表?xiàng)l目,來實(shí)現(xiàn)完整的 finally 邏輯。

反射調(diào)用為什么慢?

Java虛擬機(jī)經(jīng)典問題有哪些

默認(rèn)情況下,反射調(diào)用首先會(huì)被委派給 native 方法來進(jìn)行??上攵溥\(yùn)行效率低下。當(dāng)某個(gè)反射調(diào)用的調(diào)用次數(shù)達(dá)到 15 之后,JDK 代碼斷定該調(diào)用屬于熱點(diǎn)調(diào)用。繼而,JDK 將動(dòng)態(tài)生成直接調(diào)用目標(biāo)方法的字節(jié)碼,并將反射調(diào)用的委派對(duì)象由原本的 native 方法實(shí)現(xiàn)切換至該動(dòng)態(tài)生成的實(shí)現(xiàn)。這種方式的運(yùn)行效率相對(duì)于 native 方法來說要高很多。

之所以 JDK 不從一開始便采用動(dòng)態(tài)生成字節(jié)碼的方式,主要是因?yàn)樯蛇^程需要耗費(fèi)一定的時(shí)間。對(duì)于那些整個(gè)生命周期中僅執(zhí)行數(shù)次的反射調(diào)用,動(dòng)態(tài)生成字節(jié)碼將得不償失。

然而,即便是直接調(diào)用目標(biāo)方法的動(dòng)態(tài)實(shí)現(xiàn),其峰值性能也無法跟真正的直接調(diào)用相媲美。這背后涉及到即時(shí)編譯中的虛方法內(nèi)聯(lián)。

相關(guān)文章: < 方法內(nèi)聯(lián)(下)>

垃圾回收的基礎(chǔ)思想是什么?

Java虛擬機(jī)經(jīng)典問題有哪些

目前 JVM 的主流垃圾回收器采取的都是可達(dá)性分析算法。該算法的實(shí)質(zhì)是將一系列被稱為 GC Roots 的對(duì)象作為初始的存活對(duì)象合集,然后從該合集出發(fā)探索所有能夠被該集合引用到的對(duì)象,并標(biāo)記為存活對(duì)象。當(dāng)標(biāo)記階段結(jié)束之后,未被標(biāo)記到的對(duì)象便是可以清除的。

傳統(tǒng)的垃圾回收算法在標(biāo)記、清除過程中需要中止其他應(yīng)用線程,即所謂的 Stop-The-World。新型的垃圾回收算法,如 CMS、G1 以及 ZGC,盡可能地實(shí)現(xiàn)并發(fā)標(biāo)記、清除,從而讓 Stop-The-World 的時(shí)間長(zhǎng)度可控。

垃圾回收的另一基礎(chǔ)思想則是分代回收。JVM 會(huì)將新生成的對(duì)象劃為新生代,而將在多次垃圾回收中存活下來的對(duì)象劃為老年代。JVM 會(huì)為不同的分代設(shè)置不同的回收算法,從而達(dá)到新生代多收集、快收集,老年代少收集、全收集的目標(biāo)。

如何理解 Java 內(nèi)存模型?

現(xiàn)代計(jì)算機(jī)多為對(duì)稱多處理器的體系架構(gòu)。每個(gè)處理器均有獨(dú)立的寄存器組和緩存(這在 Java 內(nèi)存模型中被抽象為工作內(nèi)存);多個(gè)處理器可同時(shí)執(zhí)行同一進(jìn)程中的不同線程。

在 Java 程序中,不同線程可能訪問同一變量或?qū)ο?。如果任由編譯器或處理器對(duì)這些訪問進(jìn)行優(yōu)化,則很可能出現(xiàn)在單線程執(zhí)行思維下無法想象的問題。因此,Java 語言規(guī)范引入了 Java 內(nèi)存模型,通過定義多項(xiàng)規(guī)則對(duì)編譯器和處理器進(jìn)行限制。

這些規(guī)則所體現(xiàn)的最為重要的屬性便是可見性,即對(duì)某一變量的訪問能否被同一線程的其他操作,或者不同線程所觀測(cè)到。Java 內(nèi)存模型引入了多種 happens-before 關(guān)系,以實(shí)現(xiàn)上述可見性。以 volatile 字段為例,對(duì)其的寫操作 happens before 這之后的讀操作,也就是說,我們總能讀到 volatile 字段的最新值。

JVM 如何應(yīng)對(duì)對(duì)象鎖的各種場(chǎng)景?

重量級(jí)鎖是最為基礎(chǔ)、最為低效的對(duì)象鎖實(shí)現(xiàn)。JVM 會(huì)阻塞加鎖失敗的線程,并且在目標(biāo)鎖被釋放的時(shí)候,喚醒這些線程。我們用等紅燈作類比。Java 線程進(jìn)入阻塞狀態(tài)相當(dāng)于熄火停車,再次點(diǎn)火啟動(dòng)必然耗費(fèi)時(shí)間。JVM 會(huì)在進(jìn)入阻塞狀態(tài)之前進(jìn)行自旋,也就是怠速停車。如果目標(biāo)鎖能夠在短時(shí)間內(nèi)被釋放出來,該線程便能夠不進(jìn)入阻塞狀態(tài),直接獲取該鎖。

重量級(jí)鎖針對(duì)的是多個(gè)線程同時(shí)競(jìng)爭(zhēng)同一把鎖的場(chǎng)景。在現(xiàn)實(shí)中,多個(gè)線程可能在不同時(shí)間段持有同一把鎖。為了應(yīng)對(duì)這種沒有鎖競(jìng)爭(zhēng)的情況,JVM 采用了輕量級(jí)鎖機(jī)制。在加鎖時(shí),JVM 將在鎖對(duì)象處做標(biāo)記,指向當(dāng)前線程的棧上;在解鎖時(shí),上述標(biāo)記會(huì)被清除。如果某線程在請(qǐng)求鎖時(shí),發(fā)現(xiàn)該鎖為輕量級(jí)鎖,并且指向另一線程所對(duì)應(yīng)的棧,那么它會(huì)將該鎖膨脹為重量級(jí)鎖。

偏向鎖所應(yīng)對(duì)的場(chǎng)景則更為樂觀:至始至終只有一個(gè)線程請(qǐng)求某把鎖。JVM 采取的做法是在第一次加鎖時(shí)為鎖對(duì)象做標(biāo)記,使其指向當(dāng)前線程的地址;在解鎖時(shí)則不做任何操作。如果下一次請(qǐng)求該鎖的仍是同一線程,便直接跳過標(biāo)記過程;否則,JVM 會(huì)將該鎖膨脹為輕量級(jí)鎖。

“Java虛擬機(jī)經(jīng)典問題有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI