當(dāng)你使用java時(shí),遲早你會(huì)聽說Java虛擬機(jī)(JVM)。

背景
1995年,James Gosling為Sun Microsystems設(shè)計(jì)了JAVA,Java是一種多范式(即面向" />

国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁(yè) > 營(yíng)銷資訊 > 網(wǎng)站運(yùn)營(yíng) > 完整整理關(guān)于JVM — JAVA虛擬機(jī)的簡(jiǎn)介

完整整理關(guān)于JVM — JAVA虛擬機(jī)的簡(jiǎn)介

時(shí)間:2023-06-27 10:03:01 | 來源:網(wǎng)站運(yùn)營(yíng)

時(shí)間:2023-06-27 10:03:01 來源:網(wǎng)站運(yùn)營(yíng)

完整整理關(guān)于JVM — JAVA虛擬機(jī)的簡(jiǎn)介:
有性能問題,上HeapDump性能社區(qū)!
JAVA的美麗是JVM。

當(dāng)你使用java時(shí),遲早你會(huì)聽說Java虛擬機(jī)(JVM)。

背景
1995年,James Gosling為Sun Microsystems設(shè)計(jì)了JAVA,Java是一種多范式(即面向?qū)ο箢?、結(jié)構(gòu)、命令式、泛型、反光、并發(fā))編程語言,深受數(shù)百萬開發(fā)人員的喜愛。在任何給定的排名指數(shù)上,Java成為過去15年來最受歡迎的語言。在過去的15年里,開發(fā)的數(shù)萬個(gè)企業(yè)應(yīng)用程序大多是用Java編寫的,使其成為構(gòu)建企業(yè)級(jí)生產(chǎn)軟件系統(tǒng)的首選語言。盡管自從我意識(shí)到Java生態(tài)系統(tǒng)性能方面的力量以來,我一直在使用Java,它激勵(lì)著更深入地挖掘Java的世界。
JVM — JAVA虛擬機(jī)
JVM是Java生態(tài)系統(tǒng)的核心,它使基于Java的軟件程序能夠遵循WORA“寫一次,在任何地方運(yùn)行”方法。您可以在一臺(tái)機(jī)器上編寫Java代碼,并使用JVM在任何其他機(jī)器上運(yùn)行。
JVM最初設(shè)計(jì)為僅支持Java。然而,隨著時(shí)間的推移,Java平臺(tái)采用了許多其他語言,如Scala、Kotlin和Groovy。所有這些語言統(tǒng)稱為JVM語言。
JVM的工作原理,以及各種組件。
你覺得呢?什么是虛擬機(jī)?
在我們看到JVM的概念之前,讓我們看看虛擬機(jī)(VM)的概念。
虛擬機(jī)是物理計(jì)算機(jī)的虛擬表示。我們可以稱虛擬機(jī)為來賓機(jī),它運(yùn)行的物理計(jì)算機(jī)是主機(jī)。
一臺(tái)物理機(jī)器可以運(yùn)行多臺(tái)虛擬機(jī),每臺(tái)虛擬機(jī)都有自己的操作系統(tǒng)和應(yīng)用程序。這些虛擬機(jī)彼此隔離,它們看起來就像一個(gè)真正的計(jì)算機(jī)操作系統(tǒng)。


什么是Java虛擬機(jī)(JVM)?
在C和C++等編程語言中,代碼首先編譯成特定于平臺(tái)的機(jī)器代碼。這些語言被稱為編譯語言。
另一方面,在JavaScript和Python等語言中,計(jì)算機(jī)直接執(zhí)行指令,而無需編譯它們。這些語言被稱為解釋語言。
Java使用這兩種技術(shù)的組合。Java代碼首先編譯為字節(jié)代碼以生成類文件。然后,Java虛擬機(jī)為底層平臺(tái)解釋此類文件。同一類文件可以在任何平臺(tái)和操作系統(tǒng)上運(yùn)行的任何版本的JVM上執(zhí)行。
與虛擬機(jī)類似,JVM在主機(jī)上創(chuàng)建一個(gè)隔離空間。無論機(jī)器的平臺(tái)或操作系統(tǒng)如何,此空間都可以用于執(zhí)行Java程序。

Java虛擬機(jī)架構(gòu)
JVM由三個(gè)不同的組件組成:

  1. 類加載器
  2. 運(yùn)行時(shí)數(shù)據(jù)區(qū)域
  3. 執(zhí)行引擎
再來看看它們分別是什么?

類加載器
當(dāng)您編譯.java源文件時(shí),它會(huì)作為.class文件轉(zhuǎn)換為字節(jié)代碼。當(dāng)您嘗試在程序中使用此類時(shí),類加載程序會(huì)將其加載到主內(nèi)存中。
加載到內(nèi)存中的第一個(gè)類通常是包含main()方法的類。
類加載過程有三個(gè)階段:加載、鏈接和初始化。
正在加載 —
加載涉及獲取具有特定名稱的類或接口的二進(jìn)制表示(字節(jié)碼),并從中生成原始類或接口。
Java中有三個(gè)內(nèi)置的類加載程序:
Bootstrap類加載程序—這是根類加載程序。它是擴(kuò)展類加載器的超類,并加載標(biāo)準(zhǔn)Java軟件包,如java.langjava.net、java.util、java.io等。這些軟件包存在于rt.jar文件和$JAVA_HOME/jre/lib目錄中的其他核心庫(kù)中。
擴(kuò)展類加載器—這是Bootstrap類加載程序的子類和應(yīng)用程序類加載程序的超類。這加載了$JAVA_HOME/jre/lib/ext目錄中存在的標(biāo)準(zhǔn)Java庫(kù)的擴(kuò)展。
應(yīng)用程序類加載程序—這是擴(kuò)展類加載程序的最后一個(gè)類加載程序和子類。它加載類路徑上存在的文件。默認(rèn)情況下,類路徑設(shè)置為應(yīng)用程序的當(dāng)前目錄。也可以通過添加-classpath-cp命令行選項(xiàng)來修改類路徑。
JVM使用ClassLoader.loadClass()方法將類加載到內(nèi)存中。它試圖根據(jù)完全限定的名稱加載類。
如果父類加載程序找不到類,它會(huì)將工作委托給子類加載程序。如果最后一個(gè)子類加載程序也無法加載該類,它將拋出NoClassDefFoundErrorClassNotFoundException。
鏈接 —類加載到內(nèi)存中后,它會(huì)經(jīng)歷鏈接過程。鏈接類或接口涉及將程序的不同元素和依賴項(xiàng)組合在一起。
鏈接包括以下步驟:
驗(yàn)證—此階段通過根據(jù)一組約束或規(guī)則檢查.class文件來檢查其結(jié)構(gòu)正確性。如果驗(yàn)證因某種原因失敗,我們將獲得VerifyException。
例如,如果代碼是使用Java 11構(gòu)建的,但在安裝了Java 8的系統(tǒng)上運(yùn)行,則驗(yàn)證階段將失敗。
準(zhǔn)備—在此階段,JVM為類或接口的靜態(tài)字段分配內(nèi)存,并使用默認(rèn)值初始化它們。
例如,假設(shè)您在類中聲明了以下變量:
private static final boolean doit = true;
在準(zhǔn)備階段,JVM為變量doit分配內(nèi)存,并將其值設(shè)置為布爾值的默認(rèn)值,這是false的。
分辨率—在此階段,符號(hào)引用被運(yùn)行時(shí)常量池中存在的直接引用所取代。例如,如果您對(duì)其他類中存在的其他類或常量變量有引用,它們將在此階段得到解決,并替換為它們的實(shí)際引用。
初始化 —初始化涉及執(zhí)行類或接口的初始化方法(稱為<clinit>)。這可以包括調(diào)用類的構(gòu)造函數(shù),執(zhí)行靜態(tài)塊,并為所有靜態(tài)變量分配值。這是類加載的最后階段。
例如,當(dāng)我們?cè)缧r(shí)候聲明以下代碼時(shí):
private static final boolean doit= true;
在準(zhǔn)備階段,變量doit被設(shè)置為false的默認(rèn)值。在初始化階段,該變量被分配其true值。
注意—JVM是多線程的。可能會(huì)發(fā)生多個(gè)線程試圖同時(shí)初始化同一類。這可能會(huì)導(dǎo)致并發(fā)問題。您需要處理線程安全,以確保程序在多線程環(huán)境中正常工作。
運(yùn)行時(shí)數(shù)據(jù)區(qū)域
運(yùn)行時(shí)數(shù)據(jù)區(qū)域內(nèi)有五個(gè)組件
方法區(qū)域—所有類級(jí)數(shù)據(jù),如運(yùn)行時(shí)常量池、字段和方法數(shù)據(jù),以及方法和構(gòu)造函數(shù)的代碼,都存儲(chǔ)在這里。
如果方法區(qū)域中可用的內(nèi)存不足以啟動(dòng)程序,JVM會(huì)拋出OutOfMemoryError。
方法區(qū)域是在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建的,每個(gè)JVM只有一個(gè)方法區(qū)域。
堆面積—所有對(duì)象及其相應(yīng)的實(shí)例變量都存儲(chǔ)在這里。這是分配所有類實(shí)例和數(shù)組內(nèi)存的運(yùn)行時(shí)數(shù)據(jù)區(qū)域。
該堆是在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建的,每個(gè)JVM只有一個(gè)堆區(qū)域。
注意:由于方法和堆區(qū)域?yàn)槎鄠€(gè)線程共享相同的內(nèi)存,因此存儲(chǔ)在這里的數(shù)據(jù)不是線程安全的。
堆棧區(qū)域—每當(dāng)在JVM中創(chuàng)建新線程時(shí),也會(huì)同時(shí)創(chuàng)建一個(gè)單獨(dú)的運(yùn)行時(shí)堆棧。所有局部變量、方法調(diào)用和部分結(jié)果都存儲(chǔ)在堆棧區(qū)域中。
如果線程中正在完成的處理需要比可用堆棧大小更大的堆棧大小,JVM會(huì)拋出StackOverflowError。
對(duì)于每個(gè)方法調(diào)用,堆棧內(nèi)存中都有一個(gè)條目,稱為堆棧框架。當(dāng)方法調(diào)用完成后,堆??蚣軐⒈讳N毀。
堆??蚣芊譃槿齻€(gè)子部分:

注意:由于堆棧區(qū)域不是共享的,因此它本質(zhì)上是線程安全的。


程序計(jì)數(shù)器(PC)寄存器-JVM同時(shí)支持多個(gè)線程。每個(gè)線程都有自己的PC寄存器來保存當(dāng)前執(zhí)行的JVM指令的地址。指令執(zhí)行后,PC寄存器將更新為下一個(gè)指令。
原生方法堆棧-JVM包含支持本機(jī)方法的堆棧。這些方法是用Java以外的語言編寫的,例如C和C++。對(duì)于每個(gè)新線程,還分配一個(gè)單獨(dú)的本機(jī)方法堆棧。
執(zhí)行引擎—一旦字節(jié)碼加載到主內(nèi)存中,并且運(yùn)行時(shí)數(shù)據(jù)區(qū)域中有詳細(xì)信息,下一步就是運(yùn)行程序。執(zhí)行引擎通過執(zhí)行每個(gè)類中存在的代碼來處理這個(gè)問題。
但是,在執(zhí)行程序之前,字節(jié)碼需要轉(zhuǎn)換為機(jī)器語言指令。JVM可以使用解釋器或JIT編譯器作為執(zhí)行引擎。
口譯員—解釋器逐行讀取和執(zhí)行字節(jié)碼指令。由于逐行執(zhí)行,解釋器相對(duì)較慢。
解釋器的另一個(gè)缺點(diǎn)是,當(dāng)多次調(diào)用方法時(shí),每次都需要新的解釋。
JIT編譯器—JIT編譯器克服了口譯員的缺點(diǎn)。執(zhí)行引擎首先使用解釋器執(zhí)行字節(jié)代碼,但當(dāng)它找到一些重復(fù)的代碼時(shí),它使用JIT編譯器。
然后,JIT編譯器編譯整個(gè)字節(jié)碼并將其更改為本機(jī)代碼。此原生機(jī)器代碼直接用于重復(fù)的方法調(diào)用,這提高了系統(tǒng)的性能。
JIT編譯器具有以下組件:

  1. 中級(jí)代碼生成器 - 生成中間代碼
  2. 代碼優(yōu)化器—優(yōu)化中間代碼以獲得更好的性能
  3. 目標(biāo)代碼生成器-將中間代碼轉(zhuǎn)換為本機(jī)代碼
  4. 分析器—查找熱點(diǎn)(重復(fù)執(zhí)行的代碼)
注意:JIT編譯器編譯代碼比解釋器逐行解釋代碼花費(fèi)的時(shí)間要多。如果您只運(yùn)行一次程序,使用解釋器會(huì)更好。


垃圾收集器—
垃圾收集器(GC)從堆區(qū)收集和刪除未引用的對(duì)象。這是通過銷毀運(yùn)行時(shí)未使用的內(nèi)存自動(dòng)回收它們的過程。
垃圾收集使Java內(nèi)存高效,因?yàn)樗鼜亩褍?nèi)存中刪除了未引用的對(duì)象,并為新對(duì)象提供了可用空間。它涉及兩個(gè)階段:

  1. 標(biāo)記—在此步驟中,GC標(biāo)識(shí)內(nèi)存中未使用的對(duì)象
  2. 掃描—在此步驟中,GC刪除上一階段確定的對(duì)象
垃圾收集由JVM定期自動(dòng)完成,無需單獨(dú)處理。它也可以通過調(diào)用System.gc()觸發(fā),但不能保證執(zhí)行。
JVM包含3種不同類型的垃圾收集器:

  1. 串行GC—這是GC最簡(jiǎn)單的實(shí)現(xiàn),專為在單線程環(huán)境中運(yùn)行的小型應(yīng)用程序而設(shè)計(jì)。它使用單個(gè)線程進(jìn)行垃圾收集。當(dāng)它運(yùn)行時(shí),它會(huì)導(dǎo)致一個(gè)“停止世界”事件,整個(gè)應(yīng)用程序被暫停。使用串行垃圾收集器的JVM參數(shù)是-XX:+UseSerialGC
  2. 并行GC—這是JVM中GC的默認(rèn)實(shí)現(xiàn),也稱為吞吐量收集器。它使用多個(gè)線程進(jìn)行垃圾收集,但在運(yùn)行時(shí)仍然暫停應(yīng)用程序。使用并行垃圾收集器的JVM參數(shù)是-XX:+UseParallelGC。
  3. 垃圾優(yōu)先(G1)GC——G1GC專為具有大堆尺寸(超過4GB)的多線程應(yīng)用程序而設(shè)計(jì)。它將堆劃分為一組大小相等的區(qū)域,并使用多個(gè)線程掃描它們。G1GC識(shí)別垃圾最多的區(qū)域,并首先在該區(qū)域執(zhí)行垃圾收集。使用G1垃圾收集器的JVM參數(shù)是-XX:+UseG1GC
Java本機(jī)接口(JNI)——有時(shí),有必要使用本機(jī)(非Java)代碼(例如C/C++)。這可以在我們需要與硬件交互或克服Java中的內(nèi)存管理和性能約束的情況下。Java支持通過Java本機(jī)接口(JNI)執(zhí)行本機(jī)代碼。
JNI充當(dāng)橋梁,允許C、C++等其他編程語言的支持包。在您需要編寫Java不完全支持的代碼的情況下,這特別有幫助,例如一些只能用C編寫的平臺(tái)特定功能。
您可以使用本native鍵字來指示方法實(shí)現(xiàn)將由本機(jī)庫(kù)提供。您還需要調(diào)用System.loadLibrary()將共享的本機(jī)庫(kù)加載到內(nèi)存中,并將其功能提供給Java。
原生方法庫(kù)——原生方法庫(kù)是用其他編程語言編寫的庫(kù),如C、C++和匯編。這些庫(kù)通常以.dll.so文件的形式存在。這些本機(jī)庫(kù)可以通過JNI加載。


常見的JVM錯(cuò)誤


結(jié)論
在此過程中,我們討論了Java虛擬機(jī)的架構(gòu)及其各種組件。當(dāng)我們的代碼工作時(shí),它是如何工作的。
只有當(dāng)出現(xiàn)問題時(shí),我們需要拉動(dòng)JVM或修復(fù)內(nèi)存泄漏時(shí),我們才會(huì)嘗試了解其內(nèi)部機(jī)制。
原文作者:Faizan Shaikh

更多詳細(xì)深入jvm延伸內(nèi)容:

小白入門JVM必看系列小冊(cè)

JVM源碼分析專題小冊(cè)

JVM菜鳥進(jìn)階高手之路系列文章

JVM參數(shù)系列 - 學(xué)習(xí)JVM參數(shù)前必須了解的

JVM調(diào)優(yōu)工具錦囊



關(guān)鍵詞:虛擬,整理,完整

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點(diǎn)擊下載Chrome瀏覽器
關(guān)閉