1、JVM 基礎

1)JVM運行過程

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

 

Java程序經過一次編譯之後,將Java代碼編譯爲字節碼也就是.class文件,然後在不同的操作系統上依靠不同的java虛擬機進行解釋,最後再轉換爲不同平臺的機器碼,最終得到執行。

那麼瞭解了這個基本原理後,一個普通的java程序它的執行流程到底是怎樣的呢?

例如我們寫了一段這樣的代碼:

public class HelloWorld {

public static void main(String[] args) {

System.out.print("Hello world");

}

}

這段程序從編譯到運行,最終打印出“Hello world”中間經過了哪些步驟呢?

 

java代碼通過編譯之後生成字節碼文件(class文件),通過java HelloWorld執行,此時java根據系統版本找到jvm.cfg,比如我的文件:C:\Program Files\Java\jdk1.8.0_101\jre\lib\amd64\jvm.cfg。主要配置如下:

-server KNOWN

-client IGNORE

其中-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方法,最後執行。

2)JVM基本結構

可能通過上面的描述,大家對JVM運行流程有了認知,那麼JVM內部到底是怎麼執行一個class文件的呢,也就是上圖中最後一步第6步的內部細節是怎樣的呢?

因此,我們要了解JVM的內部結構:

 

由上圖所示.class文件被JVM裝載以後,經過JVM的內存空間調配,最終是由執行引擎完成.class文件的執行。當然這個過程還有其他角色模塊的協助,這些模塊協同配合才能讓一個java程序成功的運行,下面就詳細介紹這些模板,它們也是後面學習JVM最重要的部分。

內存空間:方法區、Java堆、Java棧、本地方法棧四部分組成。

方法區:是各個線程共享的區域,存放類信息、常量、靜態變量。

Java堆:是線程共享的區域,類的實例就放在這個區域,可想而知系統會產生很多實例,因此Java堆的空間也是最大的。注:如果Java堆空間不足了,程序會拋出OutOfMemoryError異常。

Java棧:是每個線程私有的區域,它的生命週期與線程相同,一個線程對應一個Java棧,每執行一個方法就會往棧中壓入一個元素,這個元素叫“棧幀”。

問題:如果Java棧空間不足了,程序會拋出StackOverflowError異常,想一想什麼情況下會容易產生這個錯誤?

對,遞歸,遞歸如果深度很深,就會執行大量的方法,方法越多Java棧的佔用空間越大。每個幀代表一個方法,Java方法有兩種返回方式,return和拋出異常,兩種方式都會導致該方法對應的幀出棧和釋放內存。

棧運行原理:棧中的數據都是以棧幀(Stack Frame)的格式存在,棧幀是一個內存區塊,是一個數據集,是一個有關方法和運行期數據的數據集。

當一個方法A被調用時就產生了一個棧幀F1,並被壓入到棧中,A方法又調用了B方法,於是產生棧幀F2也被壓入棧,B方法又調用了C方法,於是產生棧幀F3也被壓入棧…… 依次執行完畢後,先彈出後進......F3棧幀,再彈出F2棧幀,再彈出F1棧幀。------> 遵循“先進後出”/“後進先出”原則。幀的組成:局部變量區(包括方法參數和局部變量,對於instance方法,還要首先保存this類型,其中方法參數按照聲明順序嚴格放置,局部變量可以任意放置),操作數棧,幀數據區(用來幫助支持常量池的解析,正常方法返回和異常處理)。

本地方法棧:與Java棧類似,只不過它是用來表示執行本地方法的,本地方法棧存放的方法調用本地方法接口,最終調用本地方法庫,實現與操作系統、硬件交互的目的。

PC寄存器:到達這一步,類已經加載,實例對象、方法、靜態變量都有了去處。那麼程序該怎麼執行,哪個方法先執行,哪個方法後執行?

1)這些指令執行的順序就是PC寄存器在管,作用就是控制程序指令的執行順序。

2)執行引擎就是根據PC寄存器調配的指令順序,依次執行程序指令。

3)靜態變量+常量+類信息+運行時常量池存在方法區中,實例變量存在堆內存中。

4)基本類型的變量和對象的,引用變量都是在函數的棧內存中分配。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章