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出來的對象)如何存儲?看下圖
public int methodOne(int a, int b) {
Object obj = new Object();
return a + b;
}
如果局部變量是Java的8種基本基本數據類型,則存在局部變量表中,如果是引用類型。如String,局部變量表中存的是引用,而實例在堆中。
假如methodOne方法調用methodTwo方法時, 虛擬機棧的情況如下
當虛擬機棧無法再放下棧幀的時候,就會出現StackOverflowError,演示一下
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;
}
}
}
在idea中設置運行時的線程的堆棧大小為如下
-Xss 參數的作用是設置每個線程的堆棧大小
運行輸出為
-Xss參數的值越大,打印輸出的深度越大
接着解釋一下操作數棧,還是比較容易理解的
假如Test.java中有如下方法,
public int getSum(int a, int b) {
return a + b;
}
反編譯生成的Test.class文件,並輸出到show.txt中
javap -v Test.class > show.txt
show.txt的內容如下
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
解釋一下上面的語句
iload_1:局部變量1壓棧
iload_2:局部變量2壓棧
iadd:棧頂2個元素相加,計算結果壓棧
簡單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,元空間可以理解為直接的物理內存
歡迎關注
參考博客
官方介紹
[1]https://www.oracle.com/technetwork/java/javase/tech/index.html
[2]https://mp.weixin.qq.com/s/Qh9e3bNTcNRaYOft9n7rvg