0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

JVM是什么?JVM虛擬機的棧執(zhí)行原理詳細概述

Wildesbeast ? 來源:今日頭條 ? 作者:程序猿的內(nèi)心獨白 ? 2020-02-20 13:50 ? 次閱讀

什么是JVM

這個大家都應(yīng)該很熟悉了吧,JVM不就是虛擬機嗎?

Java虛擬機本質(zhì)上就是一個程序,當它在命令行上啟動的時候,就開始執(zhí)行保存在某字節(jié)碼文件中的指令。

JVM可以說離我們既熟悉又陌生,很多朋友可能在工作中接觸不到這塊技術(shù),但是在面試往往被問到(概率還蠻大),被問到了自認倒霉,死記硬背是沒用的,到頭來還是的忘,今天給大家說道說道JVM知識點,我要沒讓你明白算我輸,你可以留言噴我,如果要是可以,你們也給我點個贊成不?

初識JVM

相信這張圖大家都不陌生,這是整個Java體系,其中包括JDK.JRE.JVM三者的關(guān)系。

圖中可以看得出來JRE包含了JVM,JDK包含了JRE。

從包含的角度就是: JDK是爺爺 JRE是父親 JVM是兒子(如果覺得列子不太恰當)來看圖

我們來看代碼:

public class App {

private String name;

private Object object = new Object();

/***

* 運算

*/

public int add() {

int a = 1;

int b = 2;

int c = (a + b) * 100;

return c;

}

/**

* 程序入口

*/

public static void main(String[] args) throws InterruptedException {

App app = new App();

int result = app.add();

System.out.println(result);

}

}

我們運行上述代碼輸出結(jié)果是300,雖然這個代碼非常簡單,這個時候已經(jīng)涉及到JVM相關(guān)的知識了,在我們學Java基礎(chǔ)的時候老師就告訴我們,Java是跨平臺的,一次編寫到處運行。

那Java是怎么做到跨平臺的?繼續(xù)看下圖:

通過此圖大家就不難發(fā)現(xiàn),我們編譯的App.class文件可以在Windows操作系統(tǒng)運行也可以在Linux系統(tǒng)運行,但是兩個系統(tǒng)底層的操作指令是不一樣的,為了屏蔽底層指令的細節(jié),起到一個跨平臺的作用,JVM功不可沒,我們常說Java是跨平臺還不如說是Jvm跨平臺(JRE運行時跨平臺)。那Jvm虛擬機是怎么跨平臺的?

JVM底層原理

JVM底層由三個系統(tǒng)構(gòu)成分別是:類加載、運行時數(shù)據(jù)區(qū)、執(zhí)行引擎。

我們今天重點講解JVM運行時數(shù)據(jù)區(qū)(棧),其他兩塊可以關(guān)注我之前和后續(xù)文章。

我們App.class文件通過類加載子系統(tǒng)從硬盤中讀取文件加載到內(nèi)存中(運行時數(shù)據(jù)區(qū))。

加載完成之后怎么處理了?(打個比喻 人吃飯 》吃到肚子里》各各器官負責自己工作吸收)

Stack棧

先講一下其中的一塊內(nèi)存區(qū)域虛擬機棧,大家都知道棧是數(shù)據(jù)結(jié)構(gòu),也是線程獨有的區(qū)域,也就是每一個線程都會有自己獨立的棧區(qū)域。我們運行App.java輸出300就靠線程執(zhí)行得來的結(jié)果。是哪個線程執(zhí)行的?獲取線程快照:“main線程”

?!窋?shù)據(jù)結(jié)構(gòu)》存儲內(nèi)容》先進后出FILO

大家都知道每個方法都有自己的局部變量,比如上圖中main方法中的result,add方法中的a b c,那么java虛擬機為了區(qū)分不同方法中局部變量作用域范圍的內(nèi)存區(qū)域,每個方法在運行的時候都會分配一塊獨立的棧幀內(nèi)存區(qū)域,我們試著按上圖中的程序來簡單畫一下代碼執(zhí)行的內(nèi)存活動。

執(zhí)行main方法中的第一行代碼是,棧中會分配main()方法的棧幀,并存儲math局部變量,,接著執(zhí)行add()方法,那么棧又會分配add()的棧幀區(qū)域。

這里的棧存儲數(shù)據(jù)的方式和數(shù)據(jù)結(jié)構(gòu)中學習的棧是一樣的,先進后出。當add()方法執(zhí)行完之后,就會出棧被釋放,也就符合先進后出的特點,后調(diào)用的方法先出棧。

棧幀

棧幀內(nèi)部“數(shù)據(jù)結(jié)構(gòu)”主要由這幾個部分組成:局部變量表、操作數(shù)棧、方法出口等信息

說了半天,棧幀到底干嘛用的呀?別急講這個就會涉及到更底層的原理–字節(jié)碼。我們先看下我們上面代碼的字節(jié)碼文件。

APP.class文件看著像亂碼,其實每個都是有對應(yīng)的含義的,oracle官方是有專門的jvm字節(jié)碼指令手冊來查詢每組指令對應(yīng)的含義的。那我們研究的,當然不是這個。

jdk有自帶一個javap的命令,可以將上述class文件生成一種更可讀的字節(jié)碼文件。

Compiled from "App.java"

public com.App {

public com.App();

Code:

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: aload_0

5: new #2 // class java/lang/Object

8: dup

9: invokespecial #1 // Method java/lang/Object."":()V

12: putfield #3 // Field object:Ljava/lang/Object;

15: return

public int add();

Code:

0: iconst_1

1: istore_1

2: iconst_2

3: istore_2

4: iload_1

5: iload_2

6: iadd

7: bipush 100

9: imul

10: istore_3

11: iload_3

12: ireturn

public static void main(java.lang.String[]) throws java.lang.InterruptedException;

Code:

0: new #4 // class com/App

3: dup

4: invokespecial #5 // Method "":()V

7: astore_1

8: aload_1

9: invokevirtual #6 // Method add:()I

12: istore_2

13: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;

16: iload_2

17: invokevirtual #8 // Method java/io/PrintStream.println:(I)V

20: return

}

此時的jvm指令碼就清晰很多了,大體結(jié)構(gòu)是可以看懂的,類、靜態(tài)變量、構(gòu)造方法、add()方法、main()方法。

其中方法中的指令還是有點懵,我們舉add()方法來看一下:

Code:

0: iconst_1

1: istore_1

2: iconst_2

3: istore_2

4: iload_1

5: iload_2

6: iadd

7: bipush 100

9: imul

10: istore_3

11: iload_3

12: iretu

這幾行代碼就是對應(yīng)的我們代碼中add()方法中的四行代碼。大家都知道越底層的代碼,代碼實現(xiàn)的行數(shù)越多,因為他會包含一些java代碼在運行時底層隱藏的一些細節(jié)原理。

那么一樣的,這個jvm指令官方也是有手冊可以查閱的,網(wǎng)上也有很多翻譯版本,大家如果想了解可自行百度。

執(zhí)行流程

設(shè)計代碼中的部分指令含義:

第一步:壓棧

將int類型常量1壓入操作數(shù)棧

0: iconst_1

就是將1壓入操作數(shù)棧

更正:執(zhí)行流程過程中灰色背景“操作數(shù)?!睉?yīng)改為“局部變量表”(?。。。。。。。。。。?/p>

第二步:存儲

將int類型值存入局部變量1

1: istore_1

局部變量1,在我們代碼中也就是第一個局部變量a,先給a在局部變量表中分配內(nèi)存,然后將int類型的值,也就是目前唯一的一個1存入局部變量a

第三步:賦值

這兩行代碼就和前兩行類似了。

2: iconst_2

3: istore_2

第四步:裝載

從局部變量2中裝載int類型值

4: iload_1

5: iload_2

這兩個代碼是將局部變量1和2,也就是a和b的值裝載到操作數(shù)棧中

第五步:加法

執(zhí)行int類型的加法

6: iadd

iadd指令一執(zhí)行,會將操作數(shù)棧中的1和2依次從棧底彈出并相加,然后把運算結(jié)果3在壓入操作數(shù)棧底。

第六步:壓棧

將一個8位帶符號整數(shù)壓入棧

7: bipush 100

這個指令就是將100壓入棧

第七步:乘法

執(zhí)行int類型的乘法

9: imul

這里就類似上面的加法了,將3和100彈出棧,把結(jié)果300壓入棧

第八步:壓棧

將將int類型值存入局部變量3

10: istore_3

這里大家就不陌生了吧,和第二步第三步是一樣的,將300存入局部變量3,也就是c

第九步:裝載

從局部變量3中裝載int類型值

11: iload_3

從局表變量3加載到操作數(shù)棧

第十步:返回

返回int類型值

12: ireturn

我們add方法是被main方法中調(diào)用的,所以通過方法出口返回到mian方法中result變量存儲方法出口說白了不就是方法執(zhí)行完了之后要出到哪里,那么我們知道上面add()方法執(zhí)行完之后應(yīng)該回到main()方法第三行那么當main()方法調(diào)用add()的時候,add()棧幀中的方法出口就存儲了當前要回到的位置,那么當add()方法執(zhí)行完之后,會根據(jù)方法出口中存儲的相關(guān)信息回到main()方法的相應(yīng)位置。看我圖中的紅線

棧堆關(guān)系

main方法中除了result變量還有一個app變量,app變量指向的是一個對象。那對象是怎么存儲的?這兒要在說下局表變量表結(jié)構(gòu):基本類型和引用類型(Java叫引用C C++叫指針)

關(guān)系就是:

通過引用在棧中的app變量引用堆中的App對象

總結(jié)

講到這兒相信大家對JVM棧執(zhí)行原理是不是熟悉了?如果覺得不錯歡迎點贊評論。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2973

    瀏覽量

    104910
  • JVM
    JVM
    +關(guān)注

    關(guān)注

    0

    文章

    158

    瀏覽量

    12248
  • 虛擬機
    +關(guān)注

    關(guān)注

    1

    文章

    919

    瀏覽量

    28323
收藏 人收藏

    評論

    相關(guān)推薦

    Jvm的整體結(jié)構(gòu)和特點

    的代碼等數(shù)據(jù)?! 《褏^(qū)  所有線程共享的一塊內(nèi)存區(qū)域,虛擬機啟動時被創(chuàng)建用來存放對象實例?! ?b class='flag-5'>JVM  可以參考了解的數(shù)據(jù)結(jié)構(gòu),存放Java方法
    發(fā)表于 01-05 17:23

    Java虛擬機基礎(chǔ)

    JVM基礎(chǔ)----java虛擬機的學習內(nèi)容。
    發(fā)表于 10-30 10:21 ?0次下載

    Java:JVM虛擬機的入門知識

    Java開發(fā)現(xiàn)在面試越來越難了,進大廠必備的JVM、多線程高并發(fā)這都是最基礎(chǔ)的知識了,今天我們一起來學習Java虛擬機入門。
    的頭像 發(fā)表于 07-01 11:43 ?2329次閱讀
    Java:<b class='flag-5'>JVM</b><b class='flag-5'>虛擬機</b>的入門知識

    JVM進階知識(一):初識 JAVA

    一、前言 若想自己編寫的Java程序高效運行,以及進行正確、高效的異常診斷,JVM是不得不談的一個話題。本”JVM進階“專欄大部分內(nèi)容均來源于經(jīng)典書籍《深入理解Java虛擬機》。 二、
    的頭像 發(fā)表于 03-01 14:02 ?1054次閱讀

    JVM內(nèi)存布局的多方面了解

      JVM內(nèi)存布局規(guī)定了Java在運行過程中內(nèi)存申請、分配、管理的策略,保證了JVM的穩(wěn)定高效運行。不同的JVM對于內(nèi)存的劃分方式和管理機制存在部分差異。結(jié)合JVM
    發(fā)表于 07-08 15:09 ?418次閱讀

    JVM內(nèi)存布局詳解

    JVM內(nèi)存布局規(guī)定了Java在運行過程中內(nèi)存申請、分配、管理的策略,保證了JVM的穩(wěn)定高效運行。不同的JVM對于內(nèi)存的劃分方式和管理機制存在部分差異。結(jié)合JVM
    的頭像 發(fā)表于 04-26 10:10 ?546次閱讀
    <b class='flag-5'>JVM</b>內(nèi)存布局詳解

    詳解Java虛擬機JVM內(nèi)存布局

    JVM內(nèi)存布局規(guī)定了Java在運行過程中內(nèi)存申請、分配、管理的策略,保證了JVM的穩(wěn)定高效運行。不同的JVM對于內(nèi)存的劃分方式和管理機制存在部分差異。結(jié)合JVM
    的頭像 發(fā)表于 07-13 09:52 ?538次閱讀
    詳解Java<b class='flag-5'>虛擬機</b>的<b class='flag-5'>JVM</b>內(nèi)存布局

    OOM會導致JVM虛擬機退出嗎

    熟悉Java開發(fā)的人,應(yīng)該會經(jīng)常遇到的異常:OOM,那么這個異常會導致 JVM 虛擬機退出嗎? 1、結(jié)論 Java虛擬機JVM)在運行Java應(yīng)用時,可能會遇到內(nèi)存不足的情況,從而拋
    的頭像 發(fā)表于 09-30 10:14 ?814次閱讀

    jvm內(nèi)存模型和內(nèi)存結(jié)構(gòu)

    JVM(Java虛擬機)是Java程序的運行平臺,它負責將Java程序轉(zhuǎn)換成機器碼并在計算機上執(zhí)行。在JVM中,內(nèi)存模型和內(nèi)存結(jié)構(gòu)是兩個重要的概念,本文將
    的頭像 發(fā)表于 12-05 11:08 ?959次閱讀

    jvm調(diào)優(yōu)參數(shù)

    JVM(Java虛擬機)是Java程序的運行環(huán)境,它負責解釋Java字節(jié)碼并執(zhí)行相應(yīng)的指令。為了提高應(yīng)用程序的性能和穩(wěn)定性,我們可以調(diào)優(yōu)JVM的參數(shù)。
    的頭像 發(fā)表于 12-05 11:29 ?664次閱讀

    jvm參數(shù)的設(shè)置和jvm調(diào)優(yōu)

    JVM(Java虛擬機)參數(shù)的設(shè)置和調(diào)優(yōu)對于提高Java應(yīng)用程序的性能和穩(wěn)定性非常重要。在本文中,我們將詳細介紹JVM參數(shù)的設(shè)置和調(diào)優(yōu)方法。 一、J
    的頭像 發(fā)表于 12-05 11:36 ?1609次閱讀

    jvm運行時內(nèi)存區(qū)域劃分

    JVM是Java Virtual Machine(Java虛擬機)的縮寫,它是Java編程語言的運行環(huán)境。JVM的主要功能是將Java源代碼轉(zhuǎn)換為機器代碼,并且在運行時管理Java程序的內(nèi)存。
    的頭像 發(fā)表于 12-05 14:08 ?555次閱讀

    jvm內(nèi)存區(qū)域中,哪一塊是屬于線程共享

    JVM(Java虛擬機)是一種計算機軟件,用于執(zhí)行Java字節(jié)碼。在JVM中,存在多個內(nèi)存區(qū)域,包括線程共享的內(nèi)存區(qū)域。本文將詳細介紹
    的頭像 發(fā)表于 12-05 14:14 ?1414次閱讀

    weblogic jvm參數(shù)配置

    在WebLogic中,JVM參數(shù)配置是非常重要的,它可以對應(yīng)用程序的性能和穩(wěn)定性產(chǎn)生直接影響。JVM參數(shù)通過調(diào)整Java虛擬機的運行時行為,可以優(yōu)化內(nèi)存管理、垃圾回收以及線程管理等方面的性能。 首先
    的頭像 發(fā)表于 12-05 14:31 ?1496次閱讀

    eclipse設(shè)置jvm內(nèi)存大小

    內(nèi)存大小,并對其背后的原理進行解釋。 JVM(Java虛擬機)是Java程序的運行環(huán)境,它負責將Java字節(jié)碼翻譯成機器碼,以便在不同的平臺上執(zhí)行。JVM使用內(nèi)存來存儲運行時對象和
    的頭像 發(fā)表于 12-06 11:43 ?1928次閱讀