国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 開(kāi)發(fā) > 綜合 > 正文

深入了解JVM-----Inside JVM讀書(shū)筆記

2024-07-21 02:14:10
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

  本文首先介紹一下java虛擬機(jī)的生存周期,然后大致介紹jvm的體系結(jié)構(gòu),最后對(duì)體系結(jié)構(gòu)中的各個(gè)部分進(jìn)行詳細(xì)介紹。



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



一、 jvm的生命周期



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



jvm實(shí)例的運(yùn)行:main()作為該程序初始線(xiàn)程的起點(diǎn),任何其他線(xiàn)程均由該線(xiàn)程啟動(dòng)。jvm內(nèi)部有兩種線(xiàn)程:守護(hù)線(xiàn)程和非守護(hù)線(xiàn)程,main()屬于非守護(hù)線(xiàn)程,守護(hù)線(xiàn)程通常由jvm自己使用,java程序也可以標(biāo)明自己創(chuàng)建的線(xiàn)程是守護(hù)線(xiàn)程。



jvm實(shí)例的消亡:當(dāng)程序中的所有非守護(hù)線(xiàn)程都終止時(shí),jvm才退出;若安全管理器允許,程序也可以使用runtime類(lèi)或者system.exit()來(lái)退出。



二、jvm的體系結(jié)構(gòu)



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



 下面將先介紹類(lèi)裝載器,然后是執(zhí)行引擎,最后是運(yùn)行時(shí)數(shù)據(jù)區(qū)



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



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



用戶(hù)自定義類(lèi)裝載器: 



系統(tǒng)類(lèi)裝載器:在jvm啟動(dòng)時(shí)創(chuàng)建,用來(lái)在classpath目錄下查找要裝入的類(lèi)



其他用戶(hù)自定義類(lèi)裝載器:這里有必要先說(shuō)一下classloader類(lèi)的幾個(gè)方法,了解它們對(duì)于了解自定義類(lèi)裝載器如何裝載.class文件至關(guān)重要。



protected final class defineclass(string name, byte data[], int offset, int length)



protected final class defineclass(string name, byte data[], int offset, int length, protectiondomain protectiondomain);



protected final class findsystemclass(string name)



protected final void resolveclass(class c)



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



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



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



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



   要說(shuō)執(zhí)行引擎,就不得不的指令集,每一條指令包含一個(gè)單字節(jié)的操作碼,后面跟0個(gè)或者多個(gè)操作數(shù)。(一)指令集以棧為設(shè)計(jì)中心,而非以寄存器為中心



這種指令集設(shè)計(jì)如何滿(mǎn)足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)化的開(kāi)展。



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



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



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



主要的執(zhí)行技術(shù)有:解釋?zhuān)磿r(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)化:開(kāi)始對(duì)所有的代碼都采取解釋執(zhí)行的方式,并監(jiān)視代碼執(zhí)行情況,然后對(duì)那些經(jīng)常調(diào)用的方法啟動(dòng)一個(gè)后臺(tái)線(xiàn)程,將其編譯為本地代碼,并進(jìn)行仔細(xì)優(yōu)化。若方法不再頻繁使用,則取消編譯過(guò)的代碼,仍對(duì)其進(jìn)行解釋執(zhí)行。



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



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



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



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



(2)java棧和pc寄存器由線(xiàn)程獨(dú)享,在新線(xiàn)程創(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ù)類(lèi)型。



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



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



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



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



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



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



上邊已經(jīng)提到,方法區(qū)主要用來(lái)存儲(chǔ)jvm從class文件中提取的類(lèi)型信息,那么類(lèi)型信息是如何存儲(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ǔ)它。



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



getname(), getsuperclass(), isinterface(), getinterfaces(), getclassloader();



static變量作為類(lèi)型信息的一部分保存



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



指向class類(lèi)的引用:必然的,上邊已述



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



字段信息:普通意義上的類(lèi)型中聲明的字段



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



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



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



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



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



舉例:



class lava{



  private int speed = 5;



  void flow(){}



}



class volcano{



  public static void main(string[] args){



lava lava = new lava();



lava.flow();



}



}



運(yùn)行命令java volcano;



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



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



(3)         jvm看到new關(guān)鍵字,準(zhǔn)備為lava分配內(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í)例變量(包括自己所屬的類(lèi)和其父類(lèi)聲明的)以及指向方法區(qū)中類(lèi)數(shù)據(jù)的指針,指向方法表的指針,對(duì)象鎖(非必需), 等待集合(非必需),gc相關(guān)的數(shù)據(jù)(非必需)(主要視gc算法而定,如對(duì)于標(biāo)記并清除算法,需要標(biāo)記對(duì)象是否被引用,以及是否已調(diào)用finalize()方法)。



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



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



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



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



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



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



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



java數(shù)組的堆實(shí)現(xiàn):數(shù)組也擁有一個(gè)和他們的類(lèi)相關(guān)聯(lián)的class實(shí)例,具有相同dimension和type的數(shù)組是同一個(gè)類(lèi)的實(shí)例。數(shù)組類(lèi)名的表示:如[[ljava/lang/object 表示object[][],[i表示int[],[[[b表示byte[][][]



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



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



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



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



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



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



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



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



 



好!至此,jvm的大致介紹完畢,其他關(guān)于jvm的內(nèi)部實(shí)現(xiàn)我將陸續(xù)補(bǔ)充,歡迎大家和我探討問(wèn)題!




發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 双峰县| 美姑县| 华蓥市| 明星| 错那县| 谷城县| 巴青县| 万荣县| 南靖县| 老河口市| 湖北省| 郧西县| 泉州市| 东丰县| 宁蒗| 雅江县| 将乐县| 且末县| 贵定县| 余江县| 盐池县| 平和县| 中方县| 祥云县| 晋中市| 秭归县| 井研县| 通州区| 喀喇沁旗| 富宁县| 姚安县| 佛冈县| 黔西县| 浪卡子县| 大新县| 武平县| 军事| 红原县| 香港| 包头市| 广宗县|