1. 程式人生 > >深入理解JVM(一)——基本原理(掃盲篇)

深入理解JVM(一)——基本原理(掃盲篇)

前言

  JVM一直是java知識裡面進階階段的重要部分,如果希望在java領域研究的更深入,則JVM則是如論如何也避開不了的話題,本系列試圖通過簡潔易讀的方式,講解JVM必要的知識點。

執行流程

  我們都知道java一直宣傳的口號是:一次編譯,到處執行。那麼它如何實現的呢?我們看下圖:

image

  java程式經過一次編譯之後,將java程式碼編譯為位元組碼也就是class檔案,然後在不同的作業系統上依靠不同的java虛擬機器進行解釋,最後再轉換為不同平臺的機器碼,最終得到執行。這樣我們是不是可以推演,如果要在mac系統上執行,是不是隻需要安裝mac java虛擬機器就行了。那麼瞭解了這個基本原理後,我們嘗試去做更深的研究,一個普通的java程式它的執行流程到底是怎樣的呢?例如我們寫了一段這樣的程式碼:

public class HelloWorld { public static void main(String[] args) { System.out.print("Hello world"); } }

這段程式從編譯到執行,最終打印出“Hello world”中間經過了哪些步驟呢?我們直接上圖:

image

  java程式碼通過編譯之後生成位元組碼檔案(class檔案),通過:java HelloWorld執行,此時java根據系統版本找到jvm.cfg,各位可以搜尋一下自己電腦上的jvm.cfg檔案在哪,它會根據你的系統版本放在不同的位置,比如我的這個檔案就在:C:\Program Files\Java\jdk1.8.0_101\jre\lib\amd64\jvm.cfg,開啟看一下:

S{6G7J8WOT3$)72FL1DW5U7

  這是我電腦上的檔案,其中-server KNOWN就表示名稱為server的jvm可用。如果這時你搜索一下你電腦上jvm.dll,你就會發現它一定在你的某個server目錄下,比如我的:C:\Program Files\Java\jdk1.8.0_101\jre\bin\server\jvm.dll。簡而言之就是通過jvm.cfg檔案找到對應的jvm.dll,jvm.dll則是java虛擬機器的主要實現。接下來會初始化JVM,並且獲取JNI介面,什麼是JNI介面,就是java本地介面,你想啊java被編譯成了class檔案,JVM怎麼從硬碟上找到這個檔案並裝載到JVM裡呢,就是通過JNI介面(它還常用於java與作業系統、硬體互動),找到class檔案後並裝載進JVM,然後找到main方法,最後執行。

JVM基本結構

  可能通過上面的描述,大家對JVM執行流程有了一個粗略的認識,那麼JVM內部到底是怎麼執行一個class檔案的呢,也就是上圖中最後一步第6步的內部細節是怎樣的呢?要了解這個問題,我們首先得看一下JVM的內部結構:

image

  從這個結構不難看出,class檔案被jvm裝載以後,經過jvm的記憶體空間調配,最終是由執行引擎完成class檔案的執行。當然這個過程還有其他角色模組的協助,這些模組協同配合才能讓一個java程式成功的執行,下面就詳細介紹這些模板,它們也是後面學習jvm最重要的部分。

記憶體空間:

JVM記憶體空間包含:方法區、java堆、java棧、本地方法棧。

方法區是各個執行緒共享的區域,存放類資訊、常量、靜態變數。

java堆也是執行緒共享的區域,我們的類的例項就放在這個區域,可以想象你的一個系統會產生很多例項,因此java堆的空間也是最大的。如果java堆空間不足了,程式會丟擲OutOfMemoryError異常。

java棧是每個執行緒私有的區域,它的生命週期與執行緒相同,一個執行緒對應一個java棧,每執行一個方法就會往棧中壓入一個元素,這個元素叫“棧幀”,而棧幀中包括了方法中的區域性變數、用於存放中間狀態值的操作棧,這裡面有很多細節,我們以後再講。如果java棧空間不足了,程式會丟擲StackOverflowError異常,想一想什麼情況下會容易產生這個錯誤,對,遞迴,遞迴如果深度很深,就會執行大量的方法,方法越多java棧的佔用空間越大。

本地方法棧角色和java棧類似,只不過它是用來表示執行本地方法的,本地方法棧存放的方法呼叫本地方法介面,最終呼叫本地方法庫,實現與作業系統、硬體互動的目的。

PC暫存器,說到這裡我們的類已經載入了,例項物件、方法、靜態變數都去了自己改去的地方,那麼問題來了,程式該怎麼執行,哪個方法先執行,哪個方法後執行,這些指令執行的順序就是PC暫存器在管,它的作用就是控制程式指令的執行順序。

執行引擎當然就是根據PC暫存器調配的指令順序,依次執行程式指令。

結語

  本文主要介紹了java虛擬機器執行的基本流程,以及java虛擬機器內部結構。下一篇我們將學習java記憶體模型以及探索java變數的可見性、有序性、指令重排等問題。

ps:讀到好的文章總有中想“據為己有”的衝動,但是每次都會附錄上原作的連線,複製只為了更多人看到優秀的文章並無二意,再次感謝原作者李平。

原文連線,感謝作者李平。