JDK,JRE,JVM的聯繫是啥?
JVM Java Virtual Machine JDK Java Development Kit JRE Java Runtime Environment 看上圖官方的介紹講的很清楚
JVM的作用是啥?
JVM有2個特別有意思的特性,語言無關性和平臺無關性。
語言無關性是指實現了Java虛擬機規範的語言對可以在JVM上運行,如Groovy,和在大數據領域比較火的語言Scala,因為JVM最終運行的是class文件,只要最終的class文件複合規範就可以在JVM上運行。
平臺無關性是指安裝在不同平臺的JVM會把class文件解釋為本地的機器指令,從而實現Write Once,Run Anywhere
JVM運行時數據區
Java虛擬機在執行Java程序的過程中會把它所管理的內存劃分為若干個不同的數據區域。這些區域都有各自的用途,以及創建和銷燬的時間,有的區域隨著虛擬機進程的啟動而存在,有些區域則依賴用戶線程的啟動和結束而建立和銷燬。Java虛擬機所管理的內存將會包括以下幾個運行時數據區域
其中方法區和堆是所有線程共享的數據區 程序計數器,虛擬機棧,本地方法棧是線程隔離的數據區,畫一個邏輯圖
程序計數器
程序計數器是一塊較小的內存空間,它可以看作是當前線程所執行的字節碼的行號指示器
為什麼要記錄當前線程所執行的字節碼的行號?直接執行完不就可以了嗎?
因為代碼是在線程中運行的,線程有可能被掛起。即CPU一會執行線程A,線程A還沒有執行完被掛起了,接著執行線程B,最後又來執行線程A了,CPU得知道執行線程A的哪一部分指令,線程計數器會告訴CPU。
虛擬機棧
虛擬機棧存儲當前線程運行方法所需要的數據,指令,返回地址。虛擬機棧描述的是Java方法執行的內存模型:每個方法在執行的同時都會創建一個棧幀用於存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。每個方法從調用直至執行完成的過程,就對應著一個棧幀在虛擬機棧中從入棧道出棧的過程。
局部變量表存儲存儲局部變量,是一個定長為32位的局部變量空間。其中64位長度的long和double類型的數據會佔用2個局部變量空間(Slot),其餘的數據類型只佔用一個。引用類型(new出來的對象)如何存儲?看下圖
<code>public int methodOne(int a, int b) { Object obj = new Object(); return a + b;}/<code>
如果局部變量是Java的8種基本基本數據類型,則存在局部變量表中,如果是引用類型。如String,局部變量表中存的是引用,而實例在堆中。
假如methodOne方法調用methodTwo方法時, 虛擬機棧的情況如下
當虛擬機棧無法再放下棧幀的時候,就會出現StackOverflowError,演示一下
<code>public class JavaVMStackSOF { private int stackLength = 1; public void stackLeak() { stackLength++; stackLeak(); } public static void main(String[] args) throws Throwable { JavaVMStackSOF oom = new JavaVMStackSOF(); try { oom.stackLeak(); } catch (Throwable e) { System.out.println("stack length: " + oom.stackLength); throw e; } }}/<code>
在idea中設置運行時的線程的堆棧大小為如下
-Xss 參數的作用是設置每個線程的堆棧大小 運行輸出為
-Xss參數的值越大,打印輸出的深度越大
接著解釋一下操作數棧,還是比較容易理解的 假如Test.java中有如下方法,
<code>public int getSum(int a, int b) { return a + b;}/<code>
反編譯生成的Test.class文件,並輸出到show.txt中
<code>javap -v Test.class > show.txt/<code>
show.txt的內容如下
<code>public int getSum(int, int); descriptor: (II)I flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=3 0: iload_1 1: iload_2 2: iadd 3: ireturn LineNumberTable: line 12: 0/<code>
解釋一下上面的語句
<code>iload_1:局部變量1壓棧iload_2:局部變量2壓棧iadd:棧頂2個元素相加,計算結果壓棧/<code>
簡單2個數相加都會用到棧,這個棧就是操作數棧,更不用說複雜的語法了
本地方法棧
本地方法棧(Native Method Stack)與虛擬機棧鎖發揮的作用是非常相似的,他們之間的區別不過是虛擬機棧為虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則為虛擬機使用到的Native方法服務。
Java堆
對於大多數應用來說,Java堆(Java Heap)是Java虛擬機鎖管理的內存中最大的一塊。Java堆是所有線程共享的一塊內存區域,在虛擬機啟動時創建。此內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這裡分配內存
方法區
方法區(Method Area)與Java堆一樣,是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息,常量,靜態變量,即時編譯器編譯後的代碼等數據。
JVM內存模型
由顏色可以看出,jdk1.8之前,堆內存被分為新生代,老年代,永久帶,jdk1.8及以後堆內存被分成了新生代和老年代。新生代的區域又分為eden區,s0區,s1區,默認比例是8:1:1,元空間可以理解為直接的物理內存
Java程序員福利:金三銀四,我把最近一年經歷過的Java崗位面試,和一些刷過的面試題都做成了PDF,PDF都是可以免費分享給大家的,關注私信我:【101】,免費領取!
閱讀更多 Java架構師丨蘇先生 的文章