02.28 面試掛在JVM?別慌,圖文講解JVM工作原理,看完還不懂我跪鍵盤

JDK,JRE,JVM的聯繫是啥?

面試掛在JVM?別慌,圖文講解JVM工作原理,看完還不懂我跪鍵盤

JVM Java Virtual Machine JDK Java Development Kit JRE Java Runtime Environment 看上圖官方的介紹講的很清楚

JVM的作用是啥?

面試掛在JVM?別慌,圖文講解JVM工作原理,看完還不懂我跪鍵盤

JVM有2個特別有意思的特性,語言無關性和平臺無關性。

語言無關性是指實現了Java虛擬機規範的語言對可以在JVM上運行,如Groovy,和在大數據領域比較火的語言Scala,因為JVM最終運行的是class文件,只要最終的class文件複合規範就可以在JVM上運行。

平臺無關性是指安裝在不同平臺的JVM會把class文件解釋為本地的機器指令,從而實現Write Once,Run Anywhere

JVM運行時數據區

Java虛擬機在執行Java程序的過程中會把它所管理的內存劃分為若干個不同的數據區域。這些區域都有各自的用途,以及創建和銷燬的時間,有的區域隨著虛擬機進程的啟動而存在,有些區域則依賴用戶線程的啟動和結束而建立和銷燬。Java虛擬機所管理的內存將會包括以下幾個運行時數據區域

面試掛在JVM?別慌,圖文講解JVM工作原理,看完還不懂我跪鍵盤

其中方法區和堆是所有線程共享的數據區 程序計數器,虛擬機棧,本地方法棧是線程隔離的數據區,畫一個邏輯圖

面試掛在JVM?別慌,圖文講解JVM工作原理,看完還不懂我跪鍵盤

程序計數器

程序計數器是一塊較小的內存空間,它可以看作是當前線程所執行的字節碼的行號指示器

為什麼要記錄當前線程所執行的字節碼的行號?直接執行完不就可以了嗎?

因為代碼是在線程中運行的,線程有可能被掛起。即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>
面試掛在JVM?別慌,圖文講解JVM工作原理,看完還不懂我跪鍵盤

如果局部變量是Java的8種基本基本數據類型,則存在局部變量表中,如果是引用類型。如String,局部變量表中存的是引用,而實例在堆中。

假如methodOne方法調用methodTwo方法時, 虛擬機棧的情況如下

面試掛在JVM?別慌,圖文講解JVM工作原理,看完還不懂我跪鍵盤

當虛擬機棧無法再放下棧幀的時候,就會出現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中設置運行時的線程的堆棧大小為如下

面試掛在JVM?別慌,圖文講解JVM工作原理,看完還不懂我跪鍵盤

-Xss 參數的作用是設置每個線程的堆棧大小 運行輸出為

面試掛在JVM?別慌,圖文講解JVM工作原理,看完還不懂我跪鍵盤

-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內存模型

面試掛在JVM?別慌,圖文講解JVM工作原理,看完還不懂我跪鍵盤

由顏色可以看出,jdk1.8之前,堆內存被分為新生代,老年代,永久帶,jdk1.8及以後堆內存被分成了新生代和老年代。新生代的區域又分為eden區,s0區,s1區,默認比例是8:1:1,元空間可以理解為直接的物理內存

面試掛在JVM?別慌,圖文講解JVM工作原理,看完還不懂我跪鍵盤

Java程序員福利:金三銀四,我把最近一年經歷過的Java崗位面試,和一些刷過的面試題都做成了PDF,PDF都是可以免費分享給大家的,關注私信我:【101】,免費領取!


分享到:


相關文章: