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

首頁 > 編程 > Java > 正文

Java虛擬機(jī)底層結(jié)構(gòu)詳解

2019-11-06 08:14:56
字體:
供稿:網(wǎng)友

學(xué)習(xí)java的同學(xué)注意了!!! 學(xué)習(xí)過程中遇到什么問題或者想獲取學(xué)習(xí)資源的話,歡迎加入Java學(xué)習(xí)交流群,群號碼:523047986  我們一起學(xué)Java!

從今天開始,我將和大家一起來學(xué)習(xí)一下java虛擬機(jī)的內(nèi)容。從底層開一下java的運(yùn)行機(jī)制。

Java虛擬機(jī)

Java虛擬機(jī)(Java Virtual Machine) 簡稱JVM Java虛擬機(jī)是一個想象中的機(jī)器,在實(shí)際的計算機(jī)上通過軟件模擬來實(shí)現(xiàn)。Java虛擬機(jī)有自己想象中的硬件,如處理器、堆棧、寄存器等,還具有相應(yīng)的指令系統(tǒng)。下面我們就來看一下這幾部分比較重要的java虛擬機(jī)的結(jié)構(gòu)

JVM寄存器

所有的CPU均包含用于保存系統(tǒng)狀態(tài)和處理器所需信息的寄存器組。如果虛擬機(jī)定義義較多的寄存器,便可以從中得到更多的信息而不必對棧或內(nèi)存進(jìn)行訪問,這有利于提高運(yùn)行速度。然而,如果虛擬機(jī)中的寄存器比實(shí)際CPU的寄存器多,在實(shí)現(xiàn)虛擬機(jī)時就會占用處理器大量的時間來用常規(guī)存儲器模擬寄存器,這反而會降低虛擬機(jī)的效率。針對這種情況,JVM只設(shè)置了4個最為常用的寄存器。它們是:pc程序計數(shù)器,optop操作數(shù)棧頂指針 ,frame當(dāng)前執(zhí)行環(huán)境指針, vars指向當(dāng)前執(zhí)行環(huán)境中第一個局部變量的指針, 所有寄存器均為32位。pc用于記錄程序的執(zhí)行。optop,frame和vars用于記錄指向Java棧區(qū)的指針。

JVM棧結(jié)構(gòu)

作為基于棧結(jié)構(gòu)的計算機(jī),Java棧是JVM存儲信息的主要方法。當(dāng)JVM得到一個java字節(jié)碼應(yīng)用程序后,便為該代碼中一個類的每一個方法創(chuàng)建一個棧框架,以保存該方法的狀態(tài)信息。每個棧框架包括以下三類信息:局部變量執(zhí)行環(huán)境操作數(shù)棧 局部變量用于存儲一個類的方法中所用到的局部變量。vars寄存器指向該變量表中的第一個局部變量。執(zhí)行環(huán)境用于保存解釋器對Java字節(jié)碼進(jìn)行解釋過程中所需的信息。它們是:上次調(diào)用的方法、局部變量指針和操作數(shù)棧的棧頂和棧底指針。執(zhí)行環(huán)境是一個執(zhí)行一個方法的控制中心。例如:如果解釋器要執(zhí)行iadd(整數(shù)加法),首先要從frame寄存器中找到當(dāng)前執(zhí)行環(huán)境,而后便從執(zhí)行環(huán)境中找到操作數(shù)棧,從棧頂彈出兩個整數(shù)進(jìn)行加法運(yùn)算,最后將結(jié)果壓入棧頂。  操作數(shù)棧用于存儲運(yùn)算所需操作數(shù)及運(yùn)算的結(jié)果。

JVM碎片回收堆

Java類的實(shí)例所需的存儲空間是在堆上分配的。解釋器具體承擔(dān)為類實(shí)例分配空間的工作。解釋器在為一個實(shí)例分配完存儲空間后,便開始記錄對該實(shí)例所占用的內(nèi)存區(qū)域的使用。一旦對象使用完畢,便將其回收到堆中。在Java語言中,除了new語句外沒有其他方法為一對象申請和釋放內(nèi)存。對內(nèi)存進(jìn)行釋放和回收的工作是由Java運(yùn)行系統(tǒng)承擔(dān)的。這允許Java運(yùn)行系統(tǒng)的設(shè)計者自己決定碎片回收的方法。在SUN公司開發(fā)的Java解釋器和Hot Java環(huán)境中,碎片回收用后臺線程的方式來執(zhí)行。這不但為運(yùn)行系統(tǒng)提供了良好的性能,而且使程序設(shè)計人員擺脫了自己控制內(nèi)存使用的風(fēng)險。

JVM存儲區(qū)

  JVM有兩類存儲區(qū):常量緩沖池和方法區(qū)。常量緩沖池用于存儲類名稱、方法和字段名稱以及串常量。方法區(qū)則用于存儲Java方法的字節(jié)碼。對于這兩種存儲區(qū)域具體實(shí)現(xiàn)方式在JVM規(guī)格中沒有明確規(guī)定。這使得Java應(yīng)用程序的存儲布局必須在運(yùn)行過程中確定,依賴于具體平臺的實(shí)現(xiàn)方式。JVM是為Java字節(jié)碼定義的一種獨(dú)立于具體平臺的規(guī)格描述,是Java平臺獨(dú)立性的基礎(chǔ)。目前的JVM還存在一些限制和不足,有待于進(jìn)一步的完善,但無論如何,JVM的思想是成功的。對比分析:如果把Java原程序想象成我們的C++原程序,Java原程序編譯后生成的字節(jié)碼就相當(dāng)于C++原程序編譯后的80x86的機(jī)器碼(二進(jìn)制程序文件),JVM虛擬機(jī)相當(dāng)于80x86計算機(jī)系統(tǒng),Java解釋器相當(dāng)于80x86CPU。在80x86CPU上運(yùn)行的是機(jī)器碼,在Java解釋器上運(yùn)行的是Java字節(jié)碼。  Java解釋器相當(dāng)于運(yùn)行Java字節(jié)碼的“CPU”,但該“CPU”不是通過硬件實(shí)現(xiàn)的,而是用軟件實(shí)現(xiàn)的。Java解釋器實(shí)際上就是特定的平臺下的一個應(yīng)用程序。只要實(shí)現(xiàn)了特定平臺下的解釋器程序,Java字節(jié)碼就能通過解釋器程序在該平臺下運(yùn)行,這是Java跨平臺的根本。當(dāng)前,并不是在所有的平臺下都有相應(yīng)Java解釋器程序,這也是Java并不能在所有的平臺下都能運(yùn)行的原因,它只能在已實(shí)現(xiàn)了Java解釋器程序的平臺下運(yùn)行。 

Java虛擬機(jī)的體系結(jié)構(gòu)圖

                                                                 

Java虛擬機(jī)從啟動到結(jié)束的生命周期,當(dāng)java虛擬機(jī)啟動后,在如下幾種情況下,Java虛擬機(jī)將結(jié)束生命周期:

1.執(zhí)行了System.exit()方法 

2.程序正常執(zhí)行結(jié)束 

3.程序在執(zhí)行過程中遇到了異常或錯誤而異常終止

4.由于操作系統(tǒng)出現(xiàn)錯誤而導(dǎo)致Java虛擬機(jī)進(jìn)程終止 

Java虛擬機(jī)的棧有三個區(qū)域:局部變量區(qū)、運(yùn)行環(huán)境區(qū)、操作數(shù)區(qū)。

局部變量區(qū)

每個Java方法使用一個固定大小的局部變量集。它們按照與vars寄存器的字偏移量來尋址。局部變量都是32位的。長整數(shù)和雙精度浮點(diǎn)數(shù)占據(jù)了兩個局部變量的空間,卻按照第一個局部變量的索引來尋址。(例如,一個具有索引n的局部變量,如果是一個雙精度浮點(diǎn)數(shù),那么它實(shí)際占據(jù)了索引n和n+1所代表的存儲空間)虛擬機(jī)規(guī)范并不要求在局部變量中的64位的值是64位對齊的。虛擬機(jī)提供了把局部變量中的值裝載到操作數(shù)棧的指令,也提供了把操作數(shù)棧中的值寫入局部變量的指令。

運(yùn)行環(huán)境區(qū)

在運(yùn)行環(huán)境中包含的信息用于動態(tài)鏈接,正常的方法返回以及異常捕捉。

操作數(shù)棧區(qū)

機(jī)器指令只從操作數(shù)棧中取操作數(shù),對它們進(jìn)行操作,并把結(jié)果返回到棧中。選擇棧結(jié)構(gòu)的原因是:在只有少量寄存器或非通用寄存器的機(jī)器(如Intel486)上,也能夠高效地模擬虛擬機(jī)的行為。操作數(shù)棧是32位的。它用于給方法傳遞參數(shù),并從方法接收結(jié)果,也用于支持操作的參數(shù),并保存操作的結(jié)果。例如,iadd指令將兩個整數(shù)相加。相加的兩個整數(shù)應(yīng)該是操作數(shù)棧頂?shù)膬蓚€字。這兩個字是由先前的指令壓進(jìn)堆棧的。這兩個整數(shù)將從堆棧彈出、相加,并把結(jié)果壓回到操作數(shù)棧中。

每個原始數(shù)據(jù)類型都有專門的指令對它們進(jìn)行必須的操作。每個操作數(shù)在棧中需要一個存儲位置,除了long和double型,它們需要兩個位置。操作數(shù)只能被適用于其類型的操作符所操作。例如,壓入兩個int類型的數(shù),如果把它們當(dāng)作是一個long類型的數(shù)則是非法的。在Sun的虛擬機(jī)實(shí)現(xiàn)中,這個限制由字節(jié)碼驗(yàn)證器強(qiáng)制實(shí)行。但是,有少數(shù)操作(操作符dupe和swap),用于對運(yùn)行時數(shù)據(jù)區(qū)進(jìn)行操作時是不考慮類型的。

本地方法棧,當(dāng)一個線程調(diào)用本地方法時,它就不再受到虛擬機(jī)關(guān)于結(jié)構(gòu)和安全限制方面的約束,它既可以訪問虛擬機(jī)的運(yùn)行期數(shù)據(jù)區(qū),也可以使用本地處理器以及任何類型的棧。例如,本地棧是一個C語言的棧,那么當(dāng)C程序調(diào)用C函數(shù)時,函數(shù)的參數(shù)以某種順序被壓入棧,結(jié)果則返回給調(diào)用函數(shù)。在實(shí)現(xiàn)Java虛擬機(jī)時,本地方法接口使用的是C語言的模型棧,那么它的本地方法棧的調(diào)度與使用則完全與C語言的棧相同。

下圖可以表示出來java程序運(yùn)行的一個全過程

                                            

3  Java虛擬機(jī)的運(yùn)行過程

上面對虛擬機(jī)的各個部分進(jìn)行了比較詳細(xì)的說明,下面通過一個具體的例子來分析它的運(yùn)行過程。

虛擬機(jī)通過調(diào)用某個指定類的方法main啟動,傳遞給main一個字符串?dāng)?shù)組參數(shù),使指定的類被裝載,同時鏈接該類所使用的其它的類型,并且初始化它們。例如對于程序:

class HelloApp 

{

    public static void main(String[] args) 

    {

        System.out.PRintln("Hello World!"); 

        for (int i = 0; i < args.length; i++ )

        {

            System.out.println(args[i]);

        }

    }

}

編譯后在命令行模式下鍵入: java HelloApp run virtual machine

將通過調(diào)用HelloApp的方法main來啟動java虛擬機(jī),傳遞給main一個包含三個字符串"run"、"virtual"、"machine"的數(shù)組。現(xiàn)在我們略述虛擬機(jī)在執(zhí)行HelloApp時可能采取的步驟。

 開始試圖執(zhí)行類HelloApp的main方法,發(fā)現(xiàn)該類并沒有被裝載,也就是說虛擬機(jī)當(dāng)前不包含該類的二進(jìn)制代表,于是虛擬機(jī)使用ClassLoader試圖尋找這樣的二進(jìn)制代表。如果這個進(jìn)程失敗,則拋出一個異常。類被裝載后同時在main方法被調(diào)用之前,必須對類HelloApp與其它類型進(jìn)行鏈接然后初始化。鏈接包含三個階段:檢驗(yàn),準(zhǔn)備和解析。檢驗(yàn)檢查被裝載的主類的符號和語義,準(zhǔn)備則創(chuàng)建類或接口的靜態(tài)域以及把這些域初始化為標(biāo)準(zhǔn)的默認(rèn)值,解析負(fù)責(zé)檢查主類對其它類或接口的符號引用,在這一步它是可選的。類的初始化是對類中聲明的靜態(tài)初始化函數(shù)和靜態(tài)域的初始化構(gòu)造方法的執(zhí)行。一個類在初始化之前它的父類必須被初始化。整個過程如下:

                                       

學(xué)習(xí)Java的同學(xué)注意了!!! 學(xué)習(xí)過程中遇到什么問題或者想獲取學(xué)習(xí)資源的話,歡迎加入Java學(xué)習(xí)交流群,群號碼:523047986  我們一起學(xué)Java!


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 伊宁市| 阿城市| 四会市| 华池县| 巴林左旗| 台前县| 清原| 拜泉县| 兰西县| 衡东县| 景东| 洪江市| 丹凤县| 长治市| 临汾市| 阿城市| 特克斯县| 绩溪县| 福州市| 新营市| 砚山县| 黄陵县| 汶川县| 麻城市| 临汾市| 政和县| 壤塘县| 汾西县| 黄浦区| 九龙城区| 鄄城县| 原阳县| 陕西省| 额济纳旗| 鄂州市| 湘潭县| 鄂伦春自治旗| 昆明市| 肇源县| 衡南县| 比如县|