欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

分析JVM的組成結(jié)構(gòu)

 更新時間:2021年06月23日 10:03:56   作者:IT王小二  
JVM(虛擬機):指以軟件的方式模擬具有完整硬件系統(tǒng)功能、運行在一個完全隔離環(huán)境中的完整計算機系統(tǒng) ,是物理機的軟件實現(xiàn)。JVM和VMware,Virtual Box等虛擬機一樣,都是運行在操作系統(tǒng)之上的計算機系統(tǒng)

一、JavaSE體系

  • JavaSE,Java 平臺標準版,為 Java EE 和 Java ME 提供了基礎(chǔ)。
  • JDK:Java 開發(fā)工具包,JDK 是 JRE 的超集,包含 JRE 中的所有內(nèi)容,以及開發(fā)程序所需的編譯器和調(diào)試程序等工具。
  • JRE:Java SE 運行時環(huán)境 ,提供庫、Java 虛擬機和其他組件來運行用 Java 編程語言編寫的程序。主要類庫,包括:程序部署發(fā)布、用戶界面工具類、繼承庫、其他基礎(chǔ)庫,語言和工具基礎(chǔ)庫。
  • JVM:Java 虛擬機,負責 JavaSE 平臺的硬件和操作系統(tǒng)無關(guān)性、編譯執(zhí)行代碼(字節(jié)碼)和平臺安全性。

二、運行時數(shù)據(jù)區(qū)

  • 線程私有:程序計數(shù)器、虛擬機棧、本地方法棧。
  • 線程共享:堆、方法區(qū)。

三、程序計數(shù)器

3.1、什么是程序計數(shù)器

程序計數(shù)器是一塊較小的內(nèi)存空間,它的作用可以看作是當前線程所執(zhí)行的字節(jié)碼的行號指示器。在虛擬機的概念模型里字節(jié)碼解釋器工作時就是通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個計數(shù)器來完成。 -- 摘自《深入理解Java虛擬機》

3.2、程序計數(shù)器有什么特點

  • 程序計數(shù)器會隨著線程的啟動而創(chuàng)建,各線程之間獨立存儲,互不影響。
  • 當前線程執(zhí)行的字節(jié)碼的行號指示器。
  • 如果線程正在執(zhí)行的是一個 Java 方法,則指明當前線程執(zhí)行的代字節(jié)碼行數(shù)。
  • 如果正在執(zhí)行的是 Natvie 方法(本地方法),這個計數(shù)器值則為空(Undefined)。
  • 占用較小的內(nèi)存空間,此內(nèi)存區(qū)域是唯一一個不會出現(xiàn) OutOfMemoryError(內(nèi)存溢出) 情況的區(qū)域。

3.3、用個例子來說明

請無視我文章中取得類名,為了方便實驗演示,命名怎么快怎么來。

public class Jvm1 {

    public int test(){
        int a = 100;
        int b = 200;
        return a + b;
    }
}

這樣一個類, javac Jvm1.java,編譯成Jvm1.class文件。

再使用 javap 反匯編工具javap -c Jvm1.class看下.class文件中數(shù)據(jù)格式。

這個就是前面提到的 當前線程執(zhí)行的字節(jié)碼的行號,而程序計數(shù)器則記錄的這個數(shù)字。

  • 當然這也解釋了程序計數(shù)器不存在 OutOfMemoryError 的原因,因為它記錄的只是數(shù)字,占用空間少。
  • 同時也解釋了為什么執(zhí)行的是一個 Java 方法時,則指明當前線程執(zhí)行的代字節(jié)碼行數(shù)。
  • 而執(zhí)行 native方法 時程序計數(shù)器為 Undefined,因為 native方法 是大多是通過C實現(xiàn)并未編譯成需要執(zhí)行的字節(jié)碼指令,所以在計數(shù)器中當然是空。

四、虛擬機棧

  • 棧有什么特點? 先進后出。
  • 虛擬機棧是每個線程私有的,線程在運行時,在執(zhí)行每個方法的時候都會打包成一個 棧幀,存儲了 局部變量表,操作數(shù)據(jù)棧,動態(tài)鏈接,方法出口等信息,然后放入棧。每個時刻正在執(zhí)行的當前方法就是虛擬機棧頂?shù)臈E。方法的執(zhí)行就對應(yīng)著棧幀在虛擬機棧中入棧和出棧的過程。
  • 棧的大小缺省為 1M,可用參數(shù) –Xss 調(diào)整大小,例如-Xss256k。

一個例子來看看執(zhí)行 每個方法入棧出棧 的過程。

public class Jvm2 {

    public static void main(String[] args) {
        A();
    }

    public static void A() {
        System.out.println("A開始");
        // 此處省略100行代碼
        B(); // 調(diào)用B方法
        System.out.println("A結(jié)束");
    }

    public static void B() {
        System.out.println("B開始");
        // 此處省略100行代碼
        C(); // 調(diào)用B方法
        System.out.println("B結(jié)束");
    }

    public static void C() {
        System.out.println("C開始");
        // 此處省略100行代碼
        System.out.println("C結(jié)束");
    }
}

輸出:

A開始

B開始

C開始

C結(jié)束

B結(jié)束

A結(jié)束

4.1、局部變量表

  • 顧名思義就是局部變量的表,用于存放我們的局部變量的。
  • 主要存放我們的 Java 的八大基礎(chǔ)數(shù)據(jù)類型,如果是局部的一些對象,比如我們的 Object 對象,我們只需要存放它的一個引用地址即可。(基本數(shù)據(jù)類型、對象引用、returnAddress 類型)。

4.2、操作數(shù)據(jù)棧

  • 存放我們方法執(zhí)行的操作數(shù)的,它就是一個棧,先進后出的棧結(jié)構(gòu)。
  • 操作數(shù)棧,就是用來操作的,操作的的元素可以是任意的 java 數(shù)據(jù)類型。
  • 所以我們知道一個方法剛剛開始的時候,這個方法的操作數(shù)棧就是空的,操作數(shù)棧運行方法是會一直運行入棧/出棧的操作。

數(shù)據(jù)重疊優(yōu)化

虛擬機概念模型中每二個棧幀都是相互獨立的,但在實際應(yīng)用是我們知道一個方法調(diào)用另一個方法時,往往存在參數(shù)傳遞,這種做法在虛擬機實現(xiàn)過程中會做一些優(yōu)化,具體做法如下:令兩個棧幀出現(xiàn)一部分重疊。讓下面棧幀的一部分操作數(shù)棧與上面棧幀的部分局部變量表重疊在一起,進行方法調(diào)用時就可以共用一部分數(shù)據(jù),無須進行額外的參數(shù)復(fù)制傳遞。

4.3、動態(tài)鏈接

需要類加載、運行時才能確定具體的方法。

棧幀中會持有一個引用(符號引用),該引用指向某個具體方法。

符號引用是一個地址位置的代號,在編譯的時候我們是不知道某個方法在運行的時候是放到哪里的,這時我用代號 com/enjoy/pojo/User.Say:()V 指代某個類的方法,將來可以把符號引用轉(zhuǎn)換成直接引用進行真實的調(diào)用。用符號引用轉(zhuǎn)化成直接引用的解析時機,把解析分為兩大類:

  • 靜態(tài)解析:符號引用在類加載階段或者第一次使用的時候就直接轉(zhuǎn)換成直接引用。
  • 動態(tài)連接:符號引用在每次運行期間轉(zhuǎn)換為直接引用,即每次運行都重新轉(zhuǎn)換。

4.4、方法出口

1、正常返回(調(diào)用程序計數(shù)器中的地址作為返回)三步曲

  • 恢復(fù)上層方法的局部變量表和操作數(shù)棧
  • 把返回值(如果有的話)壓入調(diào)用者棧幀的操作數(shù)棧中
  • 調(diào)整 PC 計數(shù)器的值以指向方法調(diào)用指令后面的一條指令

2、異常返回

指方法執(zhí)行過程中遇到異常,并且這個異常在方法體內(nèi)部沒有得到處理,導(dǎo)致方法退出

4.5、棧溢出

  • java.lang.StackOverflowError:一般的方法調(diào)用是很難出現(xiàn)的,如果出現(xiàn)了要考慮是否有 無限遞歸 ,虛擬機棧帶給我們的啟示:方法的執(zhí)行因為要打包成棧楨,所以天生要比實現(xiàn)同樣功能的循環(huán)慢,所以樹的遍歷算法中:遞歸和非遞歸(循環(huán)來實現(xiàn))都有存在的意義。遞歸代碼簡潔,非遞歸代碼復(fù)雜但是速度較快。
  • OutOfMemoryError:不斷建立線程(一般演示不出,演示出來機器也死了)。

五、本地方法棧

  • 本地方法棧和虛擬機棧所發(fā)揮的作用是非常相似的,其區(qū)別不過是虛擬機棧為虛擬機執(zhí)行 Java 方法(也就是字節(jié)碼)服務(wù),而本地方法棧則是為虛擬機使用到的 Native 方法服務(wù)。
  • 虛擬機規(guī)范中對本地方法棧中的方法使用的語言、使用方式與數(shù)據(jù)結(jié)構(gòu)并沒有強制規(guī)定,因此具體的虛擬機可以自由實現(xiàn)它。
  • 本地方法棧 native 方法通過 JNI 調(diào)用到了底層的 C/C++(c/c++可以觸發(fā)匯編語言,然后驅(qū)動硬件)。
  • 當一個JVM創(chuàng)建的線程調(diào)用native方法后,JVM不再為其在虛擬機棧中創(chuàng)建棧幀,JVM只是簡單地動態(tài)鏈接并直接調(diào)用native方法。

六、方法區(qū)

主要存儲類信息、常量池、靜態(tài)變量、即時編譯期編譯后的代碼等數(shù)據(jù)。

永久代和元空間:

方法區(qū)在 jdk1.7 及其之前又背稱為永久代,jdk1.8 又被稱為元空間,怎么理解呢?

1.jdk1.8移除了永久代,新增了元空間。

2.可以理解為方法區(qū)是一個規(guī)范,但是具體怎么實現(xiàn)要看具體的jvm怎么實現(xiàn)。

3.就類似于提供了一個接口方法(規(guī)范),只要實現(xiàn)了這個接口的類,那么就要去實現(xiàn)里面接口方法(具體實現(xiàn)就是各種版本jvm之間和版本之間的差異了)。

4.各種版本jvm 。

  • HotSpot VM(SUN) 以前使用范圍最廣的Java虛擬機。
  • JRockit VM(BEA) 號稱世界上最快的JVM 。
  • Dalvik VM(Google) google自己開發(fā)的。
  • HotSPont VM(ORACLE) 目前以前使用范圍最廣的Java虛擬機。

5.版本差異(jdk1.7, jdk1.8) 。

參數(shù)設(shè)置:

  • jdk1.7 及以前:-XX:PermSize;-XX:MaxPermSize;
  • jdk1.8 以后:-XX:MetaspaceSize; -XX:MaxMetaspaceSize
  • jdk1.8 以后大小就只受本機總內(nèi)存的限制

七、堆

  • 幾乎所有對象都分配在堆內(nèi)存,也是垃圾回收發(fā)生的主要區(qū)域。
  • 堆內(nèi)存由多個線程共享。堆內(nèi)存隨著JVM啟動而創(chuàng)建。

參數(shù)設(shè)置:

-Xms:堆的最小值

-Xmx:堆的最大值

-Xmn:新生代的大小

-XX:NewSize;新生代最小值

-XX:MaxNewSize:新生代最大值

八、運行時常量池

8.1、符號引用

  • 一個 java 類(假設(shè)為 People 類)被編譯成一個 class 文件時,如果 People 類引用了 Tool 類,但是在編譯時 People 類并不知道引用類的實際內(nèi)存地址,因此只能使用符號引用來代替。
  • 而在類裝載器裝載 People 類時,此時可以通過虛擬機獲取 Tool 類的實際內(nèi)存地址,因此便可以既將符號 org.simple.Tool 替換為 Tool 類的實際內(nèi)存地址,及直接引用地址。
  • 即在編譯時用符號引用來代替引用類,在加載時再通過虛擬機獲取該引用類的實際地址。
  • 以一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用時能無歧義地定位到目標即可。符號引用與虛擬機實現(xiàn)的內(nèi)存布局是無關(guān)的,引用的目標不一定已經(jīng)加載到內(nèi)存中。

8.2、字面量

  • 文本字符串 String a = "abc",這個 abc 就是字面量。
  • 八種基本類型 int a = 1; 這個 1 就是字面量。
  • 聲明為 final 的常量。

8.3、jvm各版本運行時常量池變化

  • 運行時常量池:Class 文件中的常量池(編譯器生成的各種字面量和符號引用)會在類加載后被放入這個區(qū)域。
  • JDK1.6:運行時常量池在方法區(qū)(永久代)中。
  • JDK1.7:運行時常量池在堆中。
  • JDK1.8:去永久代:使用元空間(空間大小只受制于機器的內(nèi)存)替代永久代。

8.4、直接內(nèi)存

內(nèi)存對象分配在JVM中堆以外的內(nèi)存,也可以稱為直接內(nèi)存,這些內(nèi)存直接受操作系統(tǒng)管理(而不是JVM),這樣做的好處是能夠在一定程度上減少垃圾回收對應(yīng)用程序造成的影響。

  • 使用 Native 函數(shù)庫直接分配堆外內(nèi)存(NIO)。
  • 并不是 JVM 運行時數(shù)據(jù)區(qū)域的一部分,但是會被頻繁使用(可以通過-XX:MaxDirectMemorySize 來設(shè)置(默認與堆內(nèi)存最大值一樣,也會出現(xiàn) OOM 異常)。
  • 避免了在 Java 堆和 Native 堆中來回復(fù)制數(shù)據(jù),能夠提高效率。

以上就是分析JVM的組成結(jié)構(gòu)的詳細內(nèi)容,更多關(guān)于JVM組成結(jié)構(gòu)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論