自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

高手詳細(xì)介紹JVM是什么?

開發(fā) 后端
本文首先介紹一下Java虛擬機(jī)的生存周期,然后大致介紹JVM的體系結(jié)構(gòu),最后對(duì)體系結(jié)構(gòu)中的各個(gè)部分進(jìn)行詳細(xì)介紹。通過(guò)本文您能大概了解JVM是什么。

首先這里澄清兩個(gè)概念:JVM實(shí)例和JVM執(zhí)行引擎實(shí)例,JVM實(shí)例對(duì)應(yīng)了一個(gè)獨(dú)立運(yùn)行的Java程序,而JVM執(zhí)行引擎實(shí)例則對(duì)應(yīng)了屬于用戶運(yùn)行程序的線程;也就是JVM實(shí)例是進(jìn)程級(jí)別,而執(zhí)行引擎是線程級(jí)別的。

JVM是什么?—JVM的生命周期

JVM實(shí)例的誕生:當(dāng)啟動(dòng)一個(gè)Java程序時(shí),一個(gè)JVM實(shí)例就產(chǎn)生了,任何一個(gè)擁有publicstaticvoidmain(String[]args)函數(shù)的class都可以作為JVM實(shí)例運(yùn)行的起點(diǎn),既然如此,那么JVM如何知道是運(yùn)行classA的main而不是運(yùn)行classB的main呢?這就需要顯式的告訴JVM類名,也就是我們平時(shí)運(yùn)行Java程序命令的由來(lái),如JavaclassAhelloworld,這里Java是告訴os運(yùn)行SunJava2SDK的Java虛擬機(jī),而classA則指出了運(yùn)行JVM所需要的類名。

JVM實(shí)例的運(yùn)行:main()作為該程序初始線程的起點(diǎn),任何其他線程均由該線程啟動(dòng)。JVM內(nèi)部有兩種線程:守護(hù)線程和非守護(hù)線程,main()屬于非守護(hù)線程,守護(hù)線程通常由JVM自己使用,Java程序也可以標(biāo)明自己創(chuàng)建的線程是守護(hù)線程。JVM實(shí)例的消亡:當(dāng)程序中的所有非守護(hù)線程都終止時(shí),JVM才退出;若安全管理器允許,程序也可以使用Runtime類或者System.exit()來(lái)退出。

JVM是什么?—JVM的體系結(jié)構(gòu)

粗略分來(lái),JVM的內(nèi)部體系結(jié)構(gòu)分為三部分,分別是:類裝載器(ClassLoader)子系統(tǒng),運(yùn)行時(shí)數(shù)據(jù)區(qū),和執(zhí)行引擎。下面將先介紹類裝載器,然后是執(zhí)行引擎,最后是運(yùn)行時(shí)數(shù)據(jù)區(qū)

1,類裝載器,顧名思義,就是用來(lái)裝載.class文件的。JVM的兩種類裝載器包括:?jiǎn)?dòng)類裝載器和用戶自定義類裝載器,啟動(dòng)類裝載器是JVM實(shí)現(xiàn)的一部分,用戶自定義類裝載器則是Java程序的一部分,必須是ClassLoader類的子類。(下面所述情況是針對(duì)SunJDK1.2)

動(dòng)類裝載器:只在系統(tǒng)類(JavaAPI的類文件)的安裝路徑查找要裝入的類

用戶自定義類裝載器:

系統(tǒng)類裝載器:在JVM啟動(dòng)時(shí)創(chuàng)建,用來(lái)在CLASSPATH目錄下查找要裝入的類其他用戶自定義類裝載器:這里有必要先說(shuō)一下ClassLoader類的幾個(gè)方法,了解它們對(duì)于了解自定義類裝載器如何裝載.class文件至關(guān)重要。

  1. protectedfinalClassdefineClass(Stringname,bytedata[],intoffset,intlength)   
  2. protectedfinalClassdefineClass(Stringname,bytedata[],intoffset,intlength,ProtectionDomainprotectionDomain);protectedfinalClassfindSystemClass(Stringname)   
  3. protectedfinalvoidresolveClass(Classc)  

defineClass用來(lái)將二進(jìn)制class文件(新類型)導(dǎo)入到方法區(qū),也就是這里指的類是用戶自定義的類(也就是負(fù)責(zé)裝載類)

findSystemClass通過(guò)類型的全限定名,先通過(guò)系統(tǒng)類裝載器或者啟動(dòng)類裝載器來(lái)裝載,并返回Class對(duì)象。

ResolveClass:讓類裝載器進(jìn)行連接動(dòng)作(包括驗(yàn)證,分配內(nèi)存初始化,將類型中的符號(hào)引用解析為直接引用),這里涉及到Java命名空間的問(wèn)題,JVM保證被一個(gè)類裝載器裝載的類所引用的所有類都被這個(gè)類裝載器裝載,同一個(gè)類裝載器裝載的類之間可以相互訪問(wèn),但是不同類裝載器裝載的類看不見對(duì)方,從而實(shí)現(xiàn)了有效的屏蔽。

2,執(zhí)行引擎:它或者在執(zhí)行字節(jié)碼,或者執(zhí)行本地方法

要說(shuō)執(zhí)行引擎,就不得不的指令集,每一條指令包含一個(gè)單字節(jié)的操作碼,后面跟0個(gè)或者多個(gè)操作數(shù)。

(一)指令集以棧為設(shè)計(jì)中心,而非以寄存器為中心這種指令集設(shè)計(jì)如何滿足Java體系的要求:

平臺(tái)無(wú)關(guān)性:以棧為中心使得在只有很少register的機(jī)器上實(shí)現(xiàn)Java更便利compiler一般采用stack向連接優(yōu)化器傳遞編譯的中間結(jié)果,若指令集以stack為基礎(chǔ),則有利于運(yùn)行時(shí)進(jìn)行的優(yōu)化工作與執(zhí)行即時(shí)編譯或者自適應(yīng)優(yōu)化的執(zhí)行引擎結(jié)合,通俗的說(shuō)就是使編譯和運(yùn)行用的數(shù)據(jù)結(jié)構(gòu)統(tǒng)一,更有利于優(yōu)化的開展。

網(wǎng)絡(luò)移動(dòng)性:class文件的緊湊性。

安全性:指令集中絕大部分操作碼都指明了操作的類型。(在裝載的時(shí)候使用數(shù)據(jù)流分析期進(jìn)行一次性驗(yàn)證,而非在執(zhí)行每條指令的時(shí)候進(jìn)行驗(yàn)證,有利于提高執(zhí)行速度)。

(二)執(zhí)行技術(shù)

主要的執(zhí)行技術(shù)有:解釋,即時(shí)編譯,自適應(yīng)優(yōu)化、芯片級(jí)直接執(zhí)行其中解釋屬于第一代JVM,即時(shí)編譯JIT屬于第二代JVM,自適應(yīng)優(yōu)化(目前Sun的HotspotJVM采用這種技術(shù))則吸取第一代JVM和第二代JVM的經(jīng)驗(yàn),采用兩者結(jié)合的方式

自適應(yīng)優(yōu)化:開始對(duì)所有的代碼都采取解釋執(zhí)行的方式,并監(jiān)視代碼執(zhí)行情況,然后對(duì)那些經(jīng)常調(diào)用的方法啟動(dòng)一個(gè)后臺(tái)線程,將其編譯為本地代碼,并進(jìn)行仔細(xì)優(yōu)化。若方法不再頻繁使用,則取消編譯過(guò)的代碼,仍對(duì)其進(jìn)行解釋執(zhí)行。

3,運(yùn)行時(shí)數(shù)據(jù)區(qū):主要包括:方法區(qū),堆,Java棧,PC寄存器,本地方法棧

(1)方法區(qū)和堆由所有線程共享

堆:存放所有程序在運(yùn)行時(shí)創(chuàng)建的對(duì)象

方法區(qū):當(dāng)JVM的類裝載器加載.class文件,并進(jìn)行解析,把解析的類型信息放入方法區(qū)。

(2)Java棧和PC寄存器由線程獨(dú)享,在新線程創(chuàng)建時(shí)間里

(3)本地方法棧:存儲(chǔ)本地方法調(diào)用的狀態(tài)

上邊總體介紹了運(yùn)行時(shí)數(shù)據(jù)區(qū)的主要內(nèi)容,下邊進(jìn)行詳細(xì)介紹,要介紹數(shù)據(jù)區(qū),就不得不說(shuō)明JVM中的數(shù)據(jù)類型。

JVM中的數(shù)據(jù)類型:JVM中基本的數(shù)據(jù)單元是word,而word的長(zhǎng)度由JVM具體的實(shí)現(xiàn)者來(lái)決定

數(shù)據(jù)類型包括基本類型和引用類型,

(1)基本類型包括:數(shù)值類型(包括除boolean外的所有的Java基本數(shù)據(jù)類型),boolean(在JVM中使用int來(lái)表示,0表示false,其他int值均表示true)和returnAddress(JVM的內(nèi)部類型,用來(lái)實(shí)現(xiàn)finally子句)。

(2)引用類型包括:數(shù)組類型,類類型,接口類型

前邊講述了JVM中數(shù)據(jù)的表示,下面讓我們輸入到JVM的數(shù)據(jù)區(qū)

首先來(lái)看方法區(qū):

上邊已經(jīng)提到,方法區(qū)主要用來(lái)存儲(chǔ)JVM從class文件中提取的類型信息,那么類型信息是如何存儲(chǔ)的呢?眾所周知,Java使用的是大端序(big?endian:即低字節(jié)的數(shù)據(jù)存儲(chǔ)在高位內(nèi)存上,如對(duì)于1234,12是高位數(shù)據(jù),34為低位數(shù)據(jù),則Java中的存儲(chǔ)格式應(yīng)該為12存在內(nèi)存的低地址,34存在內(nèi)存的高地址,x86中的存儲(chǔ)格式與之相反)來(lái)存儲(chǔ)數(shù)據(jù),這實(shí)際上是在class文件中數(shù)據(jù)的存儲(chǔ)格式,但是當(dāng)數(shù)據(jù)倒入到方法區(qū)中時(shí),JVM可以以任何方式來(lái)存儲(chǔ)它。

類型信息:包括class的全限定名,class的直接父類,類類型還是接口類型,類的修飾符(public,等),所有直接父接口的列表,Class對(duì)象提供了訪問(wèn)這些信息的窗口(可通過(guò)Class.forName(“”)或instance.getClass()獲得),下面是Class的方法,相信大家看了會(huì)恍然大悟,(原來(lái)如此J)

getName(),getSuperClass(),isInterface(),getInterfaces(),getClassLoader();

static變量作為類型信息的一部分保存

指向ClassLoader類的引用:在動(dòng)態(tài)連接時(shí)裝載該類中引用的其他類

指向Class類的引用:必然的,上邊已述

該類型的常量池:包括直接常量(String,integer和floatpoint常量)以及對(duì)其他類型、字段和方法的符號(hào)引用(注意:這里的常量池并不是普通意義上的存儲(chǔ)常量的地方,這些符號(hào)引用可能是我們?cè)诰幊讨兴佑|到的變量),由于這些符號(hào)引用,使得常量池成為Java程序動(dòng)態(tài)連接中至關(guān)重要的部分

字段信息:普通意義上的類型中聲明的字段

方法信息:類型中各個(gè)方法的信息

編譯期常量:指用final聲明或者用編譯時(shí)已知的值初始化的類變量

class將所有的常量復(fù)制至其常量池或者其字節(jié)碼流中。

方法表:一個(gè)數(shù)組,包括所有它的實(shí)例可能調(diào)用的實(shí)例方法的直接引用(包括從父類中繼承來(lái)的)

除此之外,若某個(gè)類不是抽象和本地的,還要保存方法的字節(jié)碼,操作數(shù)棧和該方法的棧幀,異常表。

舉例:

  1. classLava{   
  2. privateintspeed=5;   
  3. voidflow(){}   
  4. classVolcano{   
  5. publicstaticvoidmain(String[]args){   
  6. Lavalava=newLava();   
  7. lava.flow();   
  8. }   
  9. }  

運(yùn)行命令JavaVolcano;

(1)JVM找到Volcano.class倒入,并提取相應(yīng)的類型信息到方法區(qū)。通過(guò)執(zhí)行方法區(qū)中的字節(jié)碼,JVM執(zhí)行main()方法,(執(zhí)行時(shí)會(huì)一直保存指向Vocano類的常量池的指針)

(2)Main()中第一條指令告訴JVM需為列在常量池第一項(xiàng)的類分配內(nèi)存(此處再次說(shuō)明了常量池并非只存儲(chǔ)常量信息),然后JVM找到常量池的第一項(xiàng),發(fā)現(xiàn)是對(duì)Lava類的符號(hào)引用,則檢查方法區(qū),看Lava類是否裝載,結(jié)果是還未裝載,則查找“Lava.class”,將類型信息寫入方法區(qū),并將方法區(qū)Lava類信息的指針來(lái)替換Volcano原常量池中的符號(hào)引用,即用直接引用來(lái)替換符號(hào)引用。

(3)JVM看到new關(guān)鍵字,準(zhǔn)備為L(zhǎng)ava分配內(nèi)存,根據(jù)Volcano的常量池的第一項(xiàng)找到Lava在方法區(qū)的位置,并分析需要多少對(duì)空間,確定后,在堆上分配空間,并將speed變量初始為0,并將lava對(duì)象的引用壓到棧中

(4)調(diào)用lava的flow()方法

好了,大致了解了方法區(qū)的內(nèi)容后,讓我們來(lái)看看堆

Java對(duì)象的堆實(shí)現(xiàn):

Java對(duì)象主要由實(shí)例變量(包括自己所屬的類和其父類聲明的)以及指向方法區(qū)中類數(shù)據(jù)的指針,指向方法表的指針,對(duì)象鎖(非必需),等待集合(非必需),GC相關(guān)的數(shù)據(jù)(非必需)(主要視GC算法而定,如對(duì)于標(biāo)記并清除算法,需要標(biāo)記對(duì)象是否被引用,以及是否已調(diào)用finalize()方法)。

那么為什么Java對(duì)象中要有指向類數(shù)據(jù)的指針呢?我們從幾個(gè)方面來(lái)考慮

首先:當(dāng)程序中將一個(gè)對(duì)象引用轉(zhuǎn)為另一個(gè)類型時(shí),如何檢查轉(zhuǎn)換是否允許?需用到類數(shù)據(jù)

其次:動(dòng)態(tài)綁定時(shí),并不是需要引用類型,而是需要運(yùn)行時(shí)類型,

這里的迷惑是:為什么類數(shù)據(jù)中保存的是實(shí)際類型,而非引用類型?這個(gè)問(wèn)題先留下來(lái),我想在后續(xù)的讀書筆記中應(yīng)該能明白

指向方法表的指針:這里和C++的VTBL是類似的,有利于提高方法調(diào)用的效率

對(duì)象鎖:用來(lái)實(shí)現(xiàn)多個(gè)線程對(duì)共享數(shù)據(jù)的互斥訪問(wèn)

等待集合:用來(lái)讓多個(gè)線程為完成共同目標(biāo)而協(xié)調(diào)功過(guò)。(注意Object類中的wait(),notify(),notifyAll()方法)。

Java數(shù)組的堆實(shí)現(xiàn):數(shù)組也擁有一個(gè)和他們的類相關(guān)聯(lián)的Class實(shí)例,具有相同dimension和type的數(shù)組是同一個(gè)類的實(shí)例。數(shù)組類名的表示:如[[LJava/lang/Object表示Object[][],[I表示int[],[[[B表示byte[][][]

至此,堆已大致介紹完畢,下面來(lái)介紹程序計(jì)數(shù)器和Java棧

程序計(jì)數(shù)器:為每個(gè)線程獨(dú)有,在線程啟動(dòng)時(shí)創(chuàng)建,

若thread執(zhí)行Java方法,則PC保存下一條執(zhí)行指令的地址。

若thread執(zhí)行native方法,則Pc的值為undefined

Java棧:Java棧以幀為單位保存線程的運(yùn)行狀態(tài),Java棧只有兩種操作,幀的壓棧和出棧。

每個(gè)幀代表一個(gè)方法,Java方法有兩種返回方式,return和拋出異常,兩種方式都會(huì)導(dǎo)致該方法對(duì)應(yīng)的幀出棧和釋放內(nèi)存。

幀的組成:局部變量區(qū)(包括方法參數(shù)和局部變量,對(duì)于instance方法,還要首先保存this類型,其中方法參數(shù)按照聲明順序嚴(yán)格放置,局部變量可以任意放置),操作數(shù)棧,幀數(shù)據(jù)區(qū)(用來(lái)幫助支持常量池的解析,正常方法返回和異常處理)。

本地方法棧:依賴于本地方法的實(shí)現(xiàn),如某個(gè)JVM實(shí)現(xiàn)的本地方法借口使用C連接模型,則本地方法棧就是C棧,可以說(shuō)某線程在調(diào)用本地方法時(shí),就進(jìn)入了一個(gè)不受JVM限制的領(lǐng)域,也就是JVM可以利用本地方法來(lái)動(dòng)態(tài)擴(kuò)展本身。

相信大家都明白JVM是什么了吧。

【編輯推薦】

  1. 安裝JDK后JRE與JVM聯(lián)系淺談
  2. 監(jiān)視JSP中JVM可用內(nèi)存
  3. JDK、JRE、JVM之間的關(guān)系
  4. Java之父:我們看中的并非Java語(yǔ)言,而是JVM
  5. Java虛擬機(jī)(JVM)中的內(nèi)存設(shè)置詳解
責(zé)任編輯:彭凡 來(lái)源: javaeye
相關(guān)推薦

2011-12-05 12:42:31

JavaJ2EEJVM

2011-07-13 16:14:51

DLL

2011-06-22 12:57:54

JVM

2021-05-17 15:20:03

VRAR虛擬現(xiàn)實(shí)技術(shù)

2020-06-29 14:10:28

JVM參數(shù)配置

2009-09-25 17:03:29

Hibernate是什

2011-07-05 16:15:49

面向?qū)ο?/a>

2010-09-26 10:29:45

JVMJava虛擬機(jī)

2010-03-22 16:02:50

云計(jì)算

2010-06-21 15:49:59

Linux apt是什

2009-07-09 14:26:27

JVM參數(shù)

2021-08-02 09:03:07

感知性模式互聯(lián)網(wǎng)設(shè)計(jì)

2011-07-14 13:50:09

ThreadLocal

2011-03-15 09:14:29

2019-08-12 11:14:00

JVM垃圾對(duì)象

2014-06-16 11:18:20

程序員

2022-10-08 08:34:34

JVM加載機(jī)制代碼

2011-07-28 10:40:40

Cocoa KVO

2009-07-08 18:07:58

jvm jre

2023-12-05 12:11:52

JVMCPU
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)