天天看點

JVM概念及虛拟機棧——JVM(1)

一.Java從編譯到運作的過程

1.圖示(JDK,JRE,JVM三者關系)

JVM概念及虛拟機棧——JVM(1)

​java​

​​檔案經過​

​javac​

​​的編譯後形成了​

​class​

​位元組碼檔案,然後送入JVM在JRE的類庫的幫助下進行類加載。從這張圖也可以看出JDK,JRE,JVM之間的關系。

2.三者關系

  • JVM: JVM隻是一個翻譯,把Class翻譯成機器識别的代碼,但是需要注意,JVM 不會自己生成代碼,需要大家編寫代碼,同時需要很多依賴類庫,這個時候就需要用到JRE。
  • JRE: JRE是什麼,它除了包含JVM之外,還提供了很多的類庫(就是我們說的jar包,它可以提供一些即插即用的功能,比如讀取或者操作檔案,連接配接網絡,使用I/O等等之類的)這些東西就是JRE提供的基礎類庫。JVM 标準加上實作的一大堆基礎類庫,就組成了 Java 的運作時環境,也就是我們常說的 JRE(Java Runtime Environment)。
  • JDK: 但對于程式員來說,JRE還不夠。我寫完要編譯代碼,還需要調試代碼,還需要打包代碼、有時候還需要反編譯代碼。是以我們會使用JDK,因為JDK還提供了一些非常好用的小工具,比如​

    ​javac​

    ​​(編譯代碼)、​

    ​javap​

    ​(反編譯)等。這個就是JDK。

二.JVM是一種規範

為什麼說JVM是一種規範呢?有以下兩個原因

①JVM的跨平台性

同一個Java程式,可以在多個不同的作業系統上執行,不受平台的影響(當然前提是你安裝了屬于此平台的JDK)。比如安裝了windows版本的JDK,我的Java程式就可以在windows作業系統上面運作。

②JVM的語言無關性

JVM識别的就是class檔案,不管你是什麼語言,Java也好,kotlin也好,還是你自己創的語言也好,隻要能編譯成class檔案,JVM就能識别并進行操作。

綜上,我們說JVM是一種規範。

常見的JVM實作有

JVM概念及虛拟機棧——JVM(1)

我們用的一般就是Hotspot

下面我們看一下JVM是怎麼規範的

三.JVM對記憶體的規範

JVM在執行Java程式的過程中會把它所管理的記憶體劃分為若幹個不同的資料區域,也就是對記憶體進行規範化。我們把進行規範化的這塊區域叫做運作時資料區域。裡面包含的内容如圖所示

JVM概念及虛拟機棧——JVM(1)

根據是否為線程共享,分成兩部分。

一部分是線程共享區,裡面有方法區(方法區在hotspot中有時被稱為永久代、元空間)和堆,另一部分是線程私有區,裡面有虛拟機棧,本地方法棧,程式計數器。

除了運作時資料區域之外,還有沒經過虛拟化的直接記憶體,也就是沒經過規範化的記憶體。這部分也可以被Java程式所使用。比如電腦記憶體是16G,JVM占用了5G,那麼剩下的11G就被稱為直接記憶體。但是這部分使用起來不太友善。

1.虛拟機棧講解

①概念

存儲目前線程運作java方法所需的資料,指令,傳回位址。有棧幀這個概念,一個方法就是一個棧幀。

②執行個體示範

JVM概念及虛拟機棧——JVM(1)

比如這一段程式,是在​

​main​

​​方法中​

​A​

​​調用​

​B​

​​,然後​

​B​

​​調用​

​C​

​。那麼在程式執行的過程中,虛拟機棧發生的變化是這樣的。

首先main方法是主線程,我們命名為線程1,執行main方法的時候,main方法會作為一個棧幀,進入虛拟機棧内

JVM概念及虛拟機棧——JVM(1)

然後main方法調用A方法,A方法作為另一個棧幀進入虛拟機棧

JVM概念及虛拟機棧——JVM(1)

以此類推

JVM概念及虛拟機棧——JVM(1)
JVM概念及虛拟機棧——JVM(1)

虛拟機棧還可以進行大小設定,預設值取決于平台,具體怎麼設定不用管。

這樣的話就掌握了虛拟機棧和棧幀的概念了

2.棧幀裡面有什麼

JVM概念及虛拟機棧——JVM(1)

一般來講有四個,分别是局部變量表,操作數棧,動态連接配接(這個先不管),完成出口。

  • 先解釋下程式計數器吧,它指向目前線程正在執行的位元組碼指令的位址。

我們換一張圖,繼續對棧幀進行細緻的講解

JVM概念及虛拟機棧——JVM(1)

示範程式如下

JVM概念及虛拟機棧——JVM(1)

這一部分示範程式非常簡單,就不再解釋了。我們之前說,JVM針對的是位元組碼檔案即class檔案,是以我們展示下上述代碼編譯後形成的class檔案

我們隻看​

​work​

​方法的紅框部分

JVM概念及虛拟機棧——JVM(1)

最左邊的數字,後面帶個冒号的那些數字,是位元組碼的位址,也就是位元組碼的偏移量,程式計數器儲存的就是這個值。比如程式計數器儲存着1,那麼下一步就執行​

​istore_1​

​這個指令。OK,下面讓我們來詳細示範下這個過程。

①iconst_1、istore_1

JVM概念及虛拟機棧——JVM(1)
JVM概念及虛拟機棧——JVM(1)

後面兩步和前兩步一樣.

②iconst_2、istore_2

JVM概念及虛拟機棧——JVM(1)

③然後執行iload_1、iload_2

JVM概念及虛拟機棧——JVM(1)

④iadd

JVM概念及虛拟機棧——JVM(1)

⑤bipush 10

JVM概念及虛拟機棧——JVM(1)

⑥imul

這個也是分了兩步

JVM概念及虛拟機棧——JVM(1)

後面兩步就是把這個30存到局部變量表,然後又取出來,最後通過完成出口完成,并傳回這個30。

完成出口是調用此方法的那個位置,比如這裡是在​

​main​

​方法的第三行調用的此方法

JVM概念及虛拟機棧——JVM(1)

那麼完成出口可能就記3,然後方法傳回的時候就通過3來傳回到方法調用的位置,繼續向下執行

OK,以上就是通過一段程式,來對棧幀裡面的結構進行的介紹。

3.本地方法棧

本地方法棧跟 Java 虛拟機棧的功能類似,Java 虛拟機棧用于管理 Java 函數的調用,而本地方法棧則用于管理本地方法的調用。但本地方法并不是用 Java 實作的,而是由 C 語言實作的(比如​

​Object.hashcode​

​​方法)。

本地方法棧是和虛拟機棧非常相似的一個區域,它服務的對象是 ​​

​native​

​ 方法。你甚至可以認為虛拟機棧和本地方法棧是同一個區域。HotSpot直接把本地方法棧和虛拟機棧合二為一 。

4.運作時資料區中的其他區域

JVM概念及虛拟機棧——JVM(1)

除了剛剛講的線程私有區和直接記憶體,還有方法區和堆。那麼一段程式執行後,某些代碼在哪些區域是怎麼劃分的呢?看下面的代碼

JVM概念及虛拟機棧——JVM(1)
  • ​age​

    ​​和​

    ​sex​

    ​都是靜态變量或者常量,這些是跟随着類的,會在方法區裡面。
  • 後兩個​

    ​object​

    ​​和​

    ​isKing​

    ​​是成員變量,是跟随着對象的,等對象​

    ​new​

    ​​出來之後他們才有,而對象是在堆裡面​

    ​new​

    ​的,是以他們兩個也在堆裡面。
  • ​main​

    ​​方法裡面的​

    ​x​

    ​​和​

    ​y​

    ​​還有​

    ​lobject​

    ​都是局部變量,會在局部變量表裡面。

四.深入了解JVM記憶體處理

執行個體代碼

JVM概念及虛拟機棧——JVM(1)

它運作的時候,記憶體處理的流程是

  • ①JVM申請記憶體

    ②初始化運作時資料區

    ③類加載

    ④執行方法

    ⑤建立對象

前三步完成以後,會是這個樣子

JVM概念及虛拟機棧——JVM(1)

最後建立對象,是這樣子

JVM概念及虛拟機棧——JVM(1)

那麼對象建立了,如何進行回收呢?下篇文章将會詳細講解垃圾回收機制,現在我們隻需要知道,堆可以分成兩部分,新生代和老年代,新生代又可以分成三部分

了解:JHSDB工具的使用