溫馨提示×

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

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

怎樣理解HotSpot JVM的基本原理

發(fā)布時(shí)間:2021-10-20 15:33:43 來(lái)源:億速云 閱讀:106 作者:柒染 欄目:大數(shù)據(jù)

這篇文章將為大家詳細(xì)講解有關(guān)怎樣理解HotSpot JVM的基本原理,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

關(guān)于JAVA

Java?編程語(yǔ)言是一種通用的、并發(fā)的、面向?qū)ο蟮恼Z(yǔ)言。它的語(yǔ)法類似于C和C++,但它省略了許多使C和C++復(fù)雜、混亂和不安全的特性。

Java 是幾乎所有類型的網(wǎng)絡(luò)應(yīng)用程序的基礎(chǔ),也是開(kāi)發(fā)和提供嵌入式和移動(dòng)應(yīng)用程序、游戲、基于 Web 的內(nèi)容和企業(yè)軟件的全球標(biāo)準(zhǔn)。.

從筆記本電腦到數(shù)據(jù)中心,從游戲控制臺(tái)到科學(xué)超級(jí)計(jì)算機(jī),從手機(jī)到互聯(lián)網(wǎng),Java 無(wú)處不在!

怎樣理解HotSpot JVM的基本原理

Java的技術(shù)體系主要有各種硬件平臺(tái)上的JVM虛擬機(jī)、提供各開(kāi)發(fā)領(lǐng)域接口支持的Java API、Java編程語(yǔ)言、三方Java框架(Spring等)構(gòu)成。

Java程序設(shè)計(jì)語(yǔ)言、Java虛擬機(jī)、Java API類庫(kù)這三部分統(tǒng)稱為JDK(Java Development Kit),JDK是用于支持Java程序開(kāi)發(fā)的最小環(huán)境。

可以把Java API類庫(kù)中的Java SE API子集和Java虛擬機(jī)這兩部分統(tǒng)稱為JRE(Java Runtime Environment),JRE是支持Java程序運(yùn)行的標(biāo)準(zhǔn)環(huán)境。

下圖展示了Java技術(shù)體系所包含的內(nèi)容,以及JDK和JRE所涵蓋的范圍。

怎樣理解HotSpot JVM的基本原理

關(guān)于JVM

Java虛擬機(jī)是Java平臺(tái)的基石。負(fù)責(zé)其硬件和操作系統(tǒng)的獨(dú)立性,為Java字節(jié)碼的執(zhí)行提供運(yùn)行時(shí)環(huán)境。

JVM虛擬機(jī)在Java 虛擬機(jī)規(guī)范中沒(méi)有規(guī)定具體實(shí)現(xiàn),而是有各大廠商自己實(shí)現(xiàn)。

Implementation details that are not part of the Java Virtual Machine's specification would unnecessarily constrain the creativity of implementors. For example, the memory layout of run-time data areas, the garbage-collection algorithm used, and any internal optimization of the Java Virtual Machine instructions (for example, translating them into machine code) are left to the discretion of the implementor.

Classic VM 是“世界上第一款商用Java虛擬機(jī)”,在JDK 1.2之前是Sun JDK中唯一的虛擬機(jī)。

在JDK 1.2時(shí),它與HotSpot VM并存,而在JDK 1.3時(shí),HotSpot VM成為默認(rèn)虛擬機(jī),直到JDK 1.4的時(shí)候,Classic VM才完全退出商用虛擬機(jī)的歷史舞臺(tái)。

1999年4月27日,HotSpot虛擬機(jī)發(fā)布,HotSpot最初由一家名為“Longview Technologies”的小公司開(kāi)發(fā),因?yàn)镠otSpot的優(yōu)異表現(xiàn),這家公司在1997年被Sun公司收購(gòu)了。后來(lái)它成為了JDK 1.3及之后所有版本的Sun JDK的默認(rèn)虛擬機(jī)。

在2008年和2009年,Oracle公司分別收購(gòu)了BEA公司和Sun公司,這樣Oracle就同時(shí)擁有了兩款優(yōu)秀的Java虛擬機(jī):JRockit VM和HotSpot VM。

關(guān)于HostSpot

Java HotSpot虛擬機(jī)是Sun用于Java平臺(tái)的VM。 它使用許多先進(jìn)技術(shù)為Java應(yīng)用程序提供最佳性能,包括最先進(jìn)的內(nèi)存模型,垃圾收集器和自適應(yīng)優(yōu)化器。

在SUN/Orace JDK中包括兩種風(fēng)格的VM

  • client mode

  • server mode

默認(rèn)以client mode啟動(dòng)。

啟動(dòng)命令加- server,以server mode啟動(dòng)。

查看當(dāng)前JVM mode:

怎樣理解HotSpot JVM的基本原理

兩種mode的區(qū)別:

client mode

  • 短時(shí)間內(nèi)啟動(dòng),運(yùn)行時(shí),占用更少內(nèi)存

  • C1輕量級(jí)編譯器,優(yōu)化較少

  • 適合輕量級(jí)程序和桌面程序

server mode

  • 啟動(dòng)慢,運(yùn)行時(shí),占用更大的內(nèi)存

  • C2重量級(jí)編譯器,更徹底的優(yōu)化

  • 能提供更好的性能,適合生產(chǎn)部署

HotSpot JVM Architecture

怎樣理解HotSpot JVM的基本原理

HotSpot JVM 主要包括3個(gè)組件:

  • Class Loader Subsystem

  • Runtime Data Areas

  • Execution Engine

Class Loader Subsystem

Class Loader Subsystem是JVM必不可少的核心,用于讀取/加載.class文件,并把字節(jié)碼保存在JVM方法區(qū)。

加載過(guò)程

Java虛擬機(jī)中類加載的全過(guò)程:加載,驗(yàn)證,準(zhǔn)備,解析,初始化。

怎樣理解HotSpot JVM的基本原理

Loading

Loading階段,虛擬機(jī)完成三件事情:

  1. 通過(guò)一個(gè)類的全限定名來(lái)獲取定義此類的二進(jìn)制字節(jié)流;

  2. 將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)換為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu);

  3. 在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.class對(duì)象,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的訪問(wèn)入口。

加載的第一步是在Java虛擬機(jī)外部去實(shí)現(xiàn)的,有‘類加載器’來(lái)完成加載動(dòng)作。

絕大部分Java程序都會(huì)用到以下3種系統(tǒng)提供的類加載器:

  1. 啟動(dòng)類加載器(Bootstrap ClassLoader)

    • 使用C++語(yǔ)言實(shí)現(xiàn),是虛擬機(jī)自身的一部分。

    • 加載<JAVA_HOME>/lib中虛擬機(jī)識(shí)別的jar,如rt.jar。

    • 無(wú)法被Java程序直接引用

  2. 擴(kuò)展類加載器(Extension ClassLoader)

    • 由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn)

    • 加載<JAVA_HOME>/lib/ext中類庫(kù)

    • Java程序可以直接使用

  3. 應(yīng)用程序類加載器(Application ClassLoader)

    • 由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn)

    • 也稱系統(tǒng)類加載器,加載應(yīng)用程序classpath下的jar

    • 可以直接使用,程序中默認(rèn)的類加載器

Linking

執(zhí)行類或接口的鏈接。

  • Verification,驗(yàn)證。確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,且不會(huì)危害虛擬機(jī)的安全。

  • Preparation,準(zhǔn)備。在方法區(qū)中為類變量(被static修飾的變量)分配內(nèi)存并設(shè)置初始值。

  • Resolution,解析。虛擬機(jī)將常量池的符號(hào)引用替換為直接引用。

Initialization

執(zhí)行類加載的最后階段,為所有靜態(tài)變量都分配了原始值,靜態(tài)塊從父類執(zhí)行到子類。

加載原則

  1. Delegation,委派

  2. Visibility,可見(jiàn)性

  3. Uniqueness,唯一性

Delegation

雙親委派模型

怎樣理解HotSpot JVM的基本原理

雙親委派模型在JDK1.2中被引入,要求除了啟動(dòng)類加載器,其他類加載器都要有父類加載器。

加載過(guò)程:當(dāng)一個(gè)類加載器收到加載請(qǐng)求的時(shí)候,先委派給父類加載器去完成,每個(gè)層次的類加載器都是如此,最終加載請(qǐng)求傳到頂層啟動(dòng)類加載器。如果父類無(wú)法完成加載請(qǐng)求,子類才會(huì)去嘗試加載。

破壞雙親委派模型

雙親委派解決了各類加載器的基礎(chǔ)類的統(tǒng)一問(wèn)題。

如果基礎(chǔ)類需要反調(diào)用戶代碼,怎么辦?

線程上下問(wèn)類加載器(Thread Context ClassLoader),TCCL。解決基礎(chǔ)類反調(diào)用戶代碼。例如JDK中實(shí)現(xiàn)SPI機(jī)制的JDBC、JNDI等。

Visibility

子類加載器能看到父類加載器加載的類。父類加載器看不到子類加載器中的類。

Uniqueness

父類加載器加載過(guò)的類不會(huì)被子類加載器加載。

Runtime Data Areas

怎樣理解HotSpot JVM的基本原理

Runtime Data Areas大致可以分為兩部分:

  • 線程私有區(qū),線程創(chuàng)建時(shí)分配內(nèi)存。線程啟動(dòng)時(shí)初始化,并在線程完成后銷毀,

  • 線程共享區(qū),所有線程都可以訪問(wèn)。JVM啟動(dòng)時(shí)初始化,在關(guān)閉時(shí)銷毀。

程序計(jì)數(shù)器

保存當(dāng)前正在執(zhí)行的JVM指令地址。每個(gè)線程都有自己的PC。

Java虛擬機(jī)棧

每個(gè)Java虛擬機(jī)線程都有一個(gè)私有Java虛擬機(jī)堆棧,與線程同時(shí)創(chuàng)建。

本地方法棧

供用非Java語(yǔ)言實(shí)現(xiàn)的本地方法的堆棧。換句話說(shuō),它是用來(lái)調(diào)用通過(guò)JNI(Java Native Interface Java本地接口)調(diào)用的C/C++代碼。根據(jù)具體的語(yǔ)言,一個(gè)C堆?;蛘逤++堆棧會(huì)被創(chuàng)建。

Java堆

怎樣理解HotSpot JVM的基本原理

用來(lái)保存實(shí)例或者對(duì)象的空間,而且它是垃圾回收的主要目標(biāo)。當(dāng)討論類似于JVM性能之類的問(wèn)題時(shí),它經(jīng)常會(huì)被提及。JVM提供者可以決定怎么來(lái)配置堆空間,以及不對(duì)它進(jìn)行垃圾回收。

方法區(qū)

方法區(qū)是所有線程共享的,它是在JVM啟動(dòng)的時(shí)候創(chuàng)建的。它保存所有被JVM加載的類和接口的運(yùn)行時(shí)常量池,成員變量以及方法的信息,靜態(tài)變量以及方法的字節(jié)碼。JVM的提供者可以通過(guò)不同的方式來(lái)實(shí)現(xiàn)方法區(qū)。在Oracle 的HotSpot JVM里,方法區(qū)被稱為永久區(qū)或者永久代(PermGen)。是否對(duì)方法區(qū)進(jìn)行垃圾回收對(duì)JVM的實(shí)現(xiàn)是可選的。

JDK1.8以后,PermGen被永久移除,有Metaspace(元空間)來(lái)實(shí)現(xiàn)方法區(qū)。

與永久代之間最大的區(qū)別在于:元空間并不在虛擬機(jī)中,而是使用本地內(nèi)存。

因此,默認(rèn)情況下,元空間的大小僅受本地內(nèi)存限制

運(yùn)行時(shí)常量池

這個(gè)區(qū)域和class文件里的constant_pool是相對(duì)應(yīng)的。這個(gè)區(qū)域是包含在方法區(qū)里的,不過(guò),對(duì)于JVM的操作而言,它是一個(gè)核心的角色。因此在JVM規(guī)范里特別提到了它的重要性。除了包含每個(gè)類和接口的常量,它也包含了所有方法和變量的引用。簡(jiǎn)而言之,當(dāng)一個(gè)方法或者變量被引用時(shí),JVM通過(guò)運(yùn)行時(shí)常量區(qū)來(lái)查找方法或者變量在內(nèi)存里的實(shí)際地址。

Execution Engine

怎樣理解HotSpot JVM的基本原理

Interpreter

讀取字節(jié)碼指令并以順序方式執(zhí)行。

JIT

JIT (Just In Time) Compiler。

抵消了Interpreter執(zhí)行速度慢的缺點(diǎn)并提高了性能。 JIT編譯器同時(shí)編譯字節(jié)碼的類似部分,從而減少了編譯所需的總時(shí)間。

Garbage Collection

通過(guò)收集和刪除未引用的對(duì)象來(lái)釋放內(nèi)存。

對(duì)象是否存活

在堆里面存放著Java世界幾乎所有的對(duì)象實(shí)例,垃圾收集器在對(duì)堆進(jìn)行回收前,第一件事就是要判斷對(duì)象是否存活。

引用計(jì)數(shù)算法

引用計(jì)數(shù)算法(Reference Counting)實(shí)現(xiàn)簡(jiǎn)單,判定效率也很高。給對(duì)象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)一個(gè)地方引用它時(shí),計(jì)數(shù)器值就加1;引用失效時(shí),計(jì)數(shù)器值就減1;計(jì)數(shù)器為0的對(duì)象就是不可能再被使用的。

Python語(yǔ)言、游戲腳本領(lǐng)域被廣泛應(yīng)用的Squire中都使用了引用計(jì)數(shù)算法進(jìn)行內(nèi)存管理。但是,java虛擬機(jī)里沒(méi)有用,主要原因是很難解決對(duì)象之間相互循環(huán)引用的問(wèn)題

可達(dá)性分析

可達(dá)性分析(Reachability Analysis),基本思路是通過(guò)一系列的稱為“GC Roots”的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開(kāi)始往下搜索,搜索所走過(guò)的路程稱為引用鏈(Reference Chain),當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連時(shí),則證明此對(duì)象不可用。

Java語(yǔ)言中,可作為GC Roots的對(duì)象包括以下幾種:

  • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象;

  • 方法區(qū)中類靜態(tài)屬性引用的對(duì)象

  • 方法區(qū)中常量引用的對(duì)象

  • 本地方法棧中JNI(Native方法)引用的對(duì)象

垃圾收集算法

常見(jiàn)的垃圾收集算法。

標(biāo)記-清除算法

算法分為‘標(biāo)記’、‘清除’兩個(gè)階段。

首先標(biāo)記出所有需要回收的對(duì)象,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象。

復(fù)制算法

復(fù)制(Copying),將可用內(nèi)存按容量分為大小相等的兩塊,每次只使用其中的一塊。 當(dāng)這一塊的內(nèi)存用完了,將還存活的對(duì)象復(fù)制到另外一塊上去。把已使用過(guò)的內(nèi)存空間一次清理掉。

實(shí)現(xiàn)簡(jiǎn)單,運(yùn)行高效,內(nèi)存使用率不高,用于回收新生代。

IBM研究表明,新生代中98%的對(duì)象都是在第一次GC時(shí)被回收掉,不需要按照1:1分配空間。

HotSpot虛擬機(jī)默認(rèn)Eden和Survivor比例是8:1,只有10%的內(nèi)存會(huì)被浪費(fèi)。

Survivor空間不夠時(shí),需要依賴?yán)夏甏M(jìn)行分配擔(dān)保,新生代收集下來(lái)的存活對(duì)象直接進(jìn)入老年代。

標(biāo)記-整理算法

標(biāo)記-整理(Mark-Compact)算法,標(biāo)記所有存活對(duì)象,向一端移動(dòng),然后直接清理掉端邊界意外的內(nèi)存。

分代收集算法

根據(jù)對(duì)象存活周期不同,將Java堆分為新生代和老年代。

新生代,采用復(fù)制算法。

老年代采用‘標(biāo)記-清理’或者‘標(biāo)記-整理’算法。

垃圾收集器

如果說(shuō),收集算法是內(nèi)存回收的方法論,那么,垃圾收集器就是內(nèi)存回收的具體體現(xiàn)。

Java虛擬機(jī)規(guī)范沒(méi)有規(guī)范如何實(shí)現(xiàn)垃圾收集器。不同的廠商、版本的虛擬機(jī)實(shí)現(xiàn)可能會(huì)有很大差別。

下面,基于JDK1.7 Update14之后的HotSpot虛擬機(jī)討論收集器。

怎樣理解HotSpot JVM的基本原理

Serial 收集器

"Serial" is a stop-the-world, copying collector which uses a single GC thread.

ParNew 收集器

"ParNew" is a stop-the-world, copying collector which uses multiple GC threads.

Parallel Scavenge 收集器

"Parallel Scavenge" is a stop-the-world, copying collector which uses multiple GC threads.

Serial Old 收集器

"Serial Old" is a stop-the-world, mark-sweep-compact collector that uses a single GC thread.

Parallel Old 收集器

"Parallel Old" is a compacting collector that uses multiple GC threads. Using the -XX flags for our collectors for jdk6.

CMS收集器

"CMS"(Concurrent Mark Sweep) is a mostly concurrent, low-pause collector.

G1收集器

G1(Garbage First) straddles the young generation - tenured generation boundary because it is a generational collector only in the logical sense. G1 divides the heap into regions and during a GC can collect a subset of the regions.

JMM

Java內(nèi)存模型(Java Memory Model),JMM,用來(lái)屏蔽掉各種硬件和操作系統(tǒng)之間內(nèi)存訪問(wèn)差異,以實(shí)現(xiàn)在各種平臺(tái)下一致的內(nèi)存訪問(wèn)效果。

  1. JMM主要目標(biāo)是定義程序中各個(gè)變量的訪問(wèn)規(guī)則。即在虛擬機(jī)中將變量存儲(chǔ)到內(nèi)存和從內(nèi)存中取出變量。

  2. 所有變量都存儲(chǔ)在主內(nèi)存(Main Memory),每個(gè)線程還有自己的工作內(nèi)存(Working Memory)。

  3. 線程對(duì)變量的讀取、賦值等操作都必須在工作內(nèi)存中進(jìn)行。

  4. 線程間變量值的傳遞必須通過(guò)主內(nèi)存來(lái)完成。

關(guān)于怎樣理解HotSpot JVM的基本原理就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(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