1. JVM是什么JVM是Java Virtual Machine的縮寫。它是一種基于計(jì)算設(shè)備的規(guī)范,是一臺虛擬機(jī),即虛構(gòu)的計(jì)算機(jī)。

JVM屏蔽了具體操作系統(tǒng)平臺的信息(顯然,就像是我們在電腦上開了個虛擬機(jī)一樣),當(dāng)" />

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

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁 > 營銷資訊 > 網(wǎng)站運(yùn)營 > Java基礎(chǔ):Java虛擬機(jī)(JVM)

Java基礎(chǔ):Java虛擬機(jī)(JVM)

時間:2023-07-15 01:51:02 | 來源:網(wǎng)站運(yùn)營

時間:2023-07-15 01:51:02 來源:網(wǎng)站運(yùn)營

Java基礎(chǔ):Java虛擬機(jī)(JVM):?

1. JVM是什么

JVM是Java Virtual Machine的縮寫。它是一種基于計(jì)算設(shè)備的規(guī)范,是一臺虛擬機(jī),即虛構(gòu)的計(jì)算機(jī)。

JVM屏蔽了具體操作系統(tǒng)平臺的信息(顯然,就像是我們在電腦上開了個虛擬機(jī)一樣),當(dāng)然,JVM執(zhí)行字節(jié)碼時實(shí)際上還是要解釋成具體操作平臺的機(jī)器指令的。

通過JVM,Java實(shí)現(xiàn)了平臺無關(guān)性,Java語言在不同平臺運(yùn)行時不需要重新編譯,只需要在該平臺上部署JVM就可以了。因而能實(shí)現(xiàn)一次編譯多處運(yùn)行。(就像是你的虛擬機(jī)也可以在任何安了VMWare的系統(tǒng)上運(yùn)行)

2. JRE和JDK

JRE:Java Runtime Environment,也就是JVM的運(yùn)行平臺,聯(lián)系平時用的虛擬機(jī),大概可以理解成JRE=虛擬機(jī)平臺+虛擬機(jī)本體(JVM)。類似于你電腦上的VMWare+適用于VMWare的Ubuntu虛擬機(jī)。這樣我們也就明白了JVM到底是個什么。

JDK:Java Develop Kit,Java的開發(fā)工具包,JDK本體也是Java程序,因此運(yùn)行依賴于JRE,由于需要保持JDK的獨(dú)立性與完整性,JDK的安裝目錄下通常也附有JRE。目前Oracle提供的Windows下的JDK安裝工具會同時安裝一個正常的JRE和隸屬于JDK目錄下的JRE。

3. JVM結(jié)構(gòu)

JVM主要包括:程序計(jì)數(shù)器(Program Counter),Java堆(Heap),Java虛擬機(jī)棧(Stack),本地方法棧(Native Stack),方法區(qū)(Method Area)

詳細(xì)的結(jié)構(gòu)如下:

現(xiàn)在我來分別介紹一下每一部分的功能。

3.1. 程序計(jì)數(shù)器(PC, Program Counter)

是一個寄存器,可以看作是代碼行號指示器,類似于實(shí)際計(jì)算機(jī)里的PC,用于指示,跳轉(zhuǎn)下一條需要執(zhí)行的命令。Java的基礎(chǔ)操作以及異常處理等都十分依賴PC。

JVM多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式來實(shí)現(xiàn)的。在一個確定的時刻,一個處理器(或者說多核處理器的一個內(nèi)核)只會執(zhí)行一條線程中的命令。因此,為了正常的切換線程,每個線程都會有一個獨(dú)立的PC,各線程的PC不會互相影響。這個私有的PC所占的這塊內(nèi)存即是線程的“私有內(nèi)存”。

如果線程在執(zhí)行的是Java方法,那么PC記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址。如果正在執(zhí)行的不是Java方法即Native方法,那么PC的值為undefined。

PC的內(nèi)存區(qū)域是唯一的沒有規(guī)定任何OutOfMemoryError的Java虛擬機(jī)規(guī)范中的區(qū)域。

3.2. Java虛擬機(jī)棧(Stack,Java Virtual Mechine Stacks)

同PC一樣(從工作流程圖里我們可以看到,實(shí)際上,PC也是存在于JVM Stack上的),也是線程私有的,生命周期與線程相同。虛擬機(jī)棧描述Java方法執(zhí)行的內(nèi)存模型,每個方法被執(zhí)行時都會創(chuàng)建一個棧幀(Stack Frame),棧幀會利用局部變量數(shù)組存儲局部變量(Local Variables),操作棧(Operand Stack),方法出口(Return Value),動態(tài)連接(Current Class Constant Pool Reference)等信息。

局部變量數(shù)組存儲了編譯可知的八個基本類型(int, boolean, char, short, byte, long, float, double),對象引用(根據(jù)不同的虛擬機(jī)實(shí)現(xiàn)可能是引用地址的指針或者一個handle),returnAddress類型。64位的long和double會占用兩個Slot,其余類型會占用一個Slot。在編譯期間,局部變量所需的空間就會完成分配,動態(tài)運(yùn)行期間不會改變所需的空間。

操作棧在執(zhí)行字節(jié)碼指令時會被用到,這種方式類似于原生的CPU寄存器,大部分JVM把時間花費(fèi)在操作棧的花費(fèi)上,操作棧和局部變量數(shù)組會頻繁的交換數(shù)據(jù)。

動態(tài)連接控制著運(yùn)行時常量池和棧幀的連接。所有方法和類的引用都會被當(dāng)作符號的引用存在常量池中。符號引用是實(shí)際上并不指向物理內(nèi)存地址的邏輯引用。JVM 可以選擇符號引用解析的時機(jī),一種是當(dāng)類文件加載并校驗(yàn)通過后,這種解析方式被稱為饑餓方式。另外一種是符號引用在第一次使用的時候被解析,這種解析方式稱為惰性方式。無論如何 ,JVM 必須要在第一次使用符號引用時完成解析并拋出可能發(fā)生的解析錯誤。綁定是將對象域、方法、類的符號引用替換為直接引用的過程。綁定只會發(fā)生一次。一旦綁定,符號引用會被完全替換。如果一個類的符號引用還沒有被解析,那么就會載入這個類。每個直接引用都被存儲為相對于存儲結(jié)構(gòu)(與運(yùn)行時變量或方法的位置相關(guān)聯(lián)的)偏移量。

對Java虛擬機(jī)棧這個區(qū)域,Java虛擬機(jī)規(guī)范規(guī)定了兩種異常:

3.3. 本地方法棧(Native Stack)

本地方法棧如其名字,和Java Virtual Machine Stack其實(shí)極為類似,只是執(zhí)行的是Native方法,為Native方法服務(wù)。在JVM規(guī)范中,沒有對它的實(shí)現(xiàn)做具體規(guī)定。

3.4. Java 堆(Heap, Garbage Collection Heap)

Java堆是被所有線程共享的一塊區(qū)域,在虛擬機(jī)啟動時創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對象實(shí)例,幾乎所有的對象實(shí)例都在這里分配內(nèi)存(隨著技術(shù)的發(fā)展,已不絕對)。

Java堆是垃圾收集器管理的主要區(qū)域,因而也被稱為GC堆。收集器采用分代回收法,GC堆可以分為新生代(Yong Generation)和老生代(Old Generation)。新生代包括Eden Space和Survivor Space。但無論哪個區(qū)域,如何劃分,存儲的都是Java對象實(shí)例,進(jìn)一步的劃分是為了更好的回收內(nèi)存或快速的分配內(nèi)存。

根據(jù)Java虛擬機(jī)規(guī)范,堆所在的物理內(nèi)存區(qū)間可以是不連續(xù)的,只要邏輯連續(xù)就可以。實(shí)現(xiàn)時既可以是固定大小,也可以是可擴(kuò)展的。如果堆無法擴(kuò)展時,就會拋出OutOfMemoryError。

3.5. 方法區(qū)(Method Area)

方法區(qū)和Java堆類似,也屬于各線程共享的內(nèi)存區(qū)域。用于存儲已被虛擬機(jī)加載的類信息,常量,靜態(tài)變量,即時編譯器編譯后的代碼數(shù)據(jù)等。它屬于非堆區(qū)(Non Heap),和Java堆區(qū)分開。對于存在永久代(Permanent)概念的虛擬機(jī)(HotSpot)而言,方法區(qū)存在于永久代。Java虛擬機(jī)規(guī)范對方法區(qū)的規(guī)定很寬松,甚至可以不實(shí)現(xiàn)GC。不過并非進(jìn)入方法區(qū)的數(shù)據(jù)就會永久存在了,這塊區(qū)域的內(nèi)存回收主要為常量池的回收和類型的卸載。這個區(qū)域的回收處理不善也會導(dǎo)致嚴(yán)重的內(nèi)存泄漏。

當(dāng)方法區(qū)無法滿足內(nèi)存分配需求時也會拋出OutOfMemoryError。

3.6. 代碼緩存(Code Cache)

用于編譯和存儲那些被 JIT 編譯器編譯成原生代碼的方法。

3.7. 類信息(Class Data)

類信息存儲在方法區(qū),其主要構(gòu)成為運(yùn)行時常量池(Run-Time Constant Pool)和方法(Method Code)。

一個編譯后的類文件包括以下結(jié)構(gòu):

?

結(jié)構(gòu)解釋
magic, minor_version, major_version類文件的版本信息和用于編譯這個類的 JDK 版本。
constant_pool類似于符號表,盡管它包含更多數(shù)據(jù)。下面有更多的詳細(xì)描述。
access_flags提供這個類的描述符列表。
this_class提供這個類全名的常量池(constant_pool)索引,比如org/jamesdbloom/foo/Bar。
super_class提供這個類的父類符號引用的常量池索引。
interfaces指向常量池的索引數(shù)組,提供那些被實(shí)現(xiàn)的接口的符號引用。
fields提供每個字段完整描述的常量池索引數(shù)組。
methods指向constant_pool的索引數(shù)組,用于表示每個方法簽名的完整描述。如果這個方法不是抽象方法也不是 native 方法,那么就會顯示這個函數(shù)的字節(jié)碼。
attributes不同值的數(shù)組,表示這個類的附加信息,包括 RetentionPolicy.CLASS 和 RetentionPolicy.RUNTIME 注解。
?

3.8. 運(yùn)行時常量池(Run-Time Constant Pool)

運(yùn)行時常量池是方法區(qū)的一部分。Class文件中有類的版本,字段,方法,接口等描述信息和用于存放編譯期生成的各種字面量和符號引用。這部分內(nèi)容將在類加載后存放到方法區(qū)的運(yùn)行時常量池中。Java虛擬機(jī)規(guī)范對Class的細(xì)節(jié)有著嚴(yán)苛的要求而對運(yùn)行時常量池的實(shí)現(xiàn)不做要求。一般來說除了翻譯的Class,翻譯出來的直接引用也會存在運(yùn)行時常量池中。

運(yùn)行時常量池具備動態(tài)性,即運(yùn)行時也可將新的常量放入池中。比如String類的intern()方法。

常量池?zé)o法申請到足夠的內(nèi)存分配時也會拋出OutOfMemoryError。

3.9. 直接內(nèi)存(Direct Memory)

直接內(nèi)存并不在Java虛擬機(jī)規(guī)范中,不是Java的一部分,但是也被頻繁使用并可能導(dǎo)致OutOfMemoryError。Native函數(shù)庫可以直接分配堆外內(nèi)存,通過存儲在Java堆里的DirectDataBuffer對象作為這塊內(nèi)存的引用進(jìn)行操作。這樣做在一些場景中可以顯著提高性能。

直接內(nèi)存是堆外內(nèi)存,自然不受Java堆大小的限制,但是可能受實(shí)體機(jī)內(nèi)存大小的限制。如果內(nèi)存各部分總和大于實(shí)體機(jī)的內(nèi)存時,也會報(bào)出OutOfMemoryError。

4. Java垃圾回收

將內(nèi)存中不再被使用的對象進(jìn)行回收,GC中用于回收的方法稱為收集器,由于GC需要消耗一些資源和時間,Java在對對象的生命周期特征進(jìn)行分析后,按照新生代、舊生代的方式來對對象進(jìn)行收集,以盡可能的縮短GC對應(yīng)用造成的暫停。

不同的對象引用類型, GC會采用不同的方法進(jìn)行回收,JVM對象的引用分為了四種類型:

5. JVM線程與原生線程的關(guān)系

JVM允許一個程序使用多個并發(fā)線程,Hotspot JVM中Java的線程與原生操作系統(tǒng)的線程是直接映射關(guān)系。即當(dāng)線程本地存儲、緩沖區(qū)分配、同步對象、棧、程序計(jì)數(shù)器等準(zhǔn)備好以后,就會創(chuàng)建一個操作系統(tǒng)原生線程。Java 線程結(jié)束,原生線程隨之被回收。操作系統(tǒng)負(fù)責(zé)調(diào)度所有線程,并把它們分配到任何可用的 CPU 上。當(dāng)原生線程初始化完畢,就會調(diào)用 Java 線程的 run() 方法。run() 返回時,被處理未捕獲異常,原生線程將確認(rèn)由于它的結(jié)束是否要終止 JVM 進(jìn)程(比如這個線程是最后一個非守護(hù)線程)。當(dāng)線程結(jié)束時,會釋放原生線程和 Java 線程的所有資源。




版權(quán)聲明:本文為博客園博主CieloSun的原創(chuàng)文章,
原文鏈接:Java基礎(chǔ):Java虛擬機(jī)(JVM) - CieloSun - 博客園

?

關(guān)鍵詞:虛擬,基礎(chǔ)

74
73
25
news

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

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