jvm原理和代碼運行的過程


一次編譯,到處運行

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

graph TD java原程序--javac編譯-->java字節碼 java字節碼-->jvm虛擬機 jvm虛擬機--java解釋-->windows機器碼 jvm虛擬機--java解釋-->linux機器碼 windows機器碼-->windows執行 linux機器碼-->linux執行

java程序經過一次編譯之后,將java代碼編譯為字節碼也就是class文件,然后在不同的操作系統上依靠不同的java虛擬機進行解釋,最后再轉換為不同平台的機器碼,最終得到執行。這樣我們是不是可以推演,如果要在mac系統上運行,是不是只需要安裝mac java虛擬機就行了。那么了解了這個基本原理后,我們來看一下,一段程序是如何執行的。

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

這段程序從編譯到運行,所經歷的過程如下:

graph TD java源代碼--class文件-->java字節碼 java字節碼--加載jvm.cfg文件-->加載配置 加載配置--根據jvm.cfg的配置-->加載jvm.dll文件 加載jvm.dll文件-->初始化jvm 初始化jvm-->獲取JNI接口 獲取JNI接口--JNI為本地方法他可以直接與操作系統交互-->操作Class文件 操作Class文件-->找到main文件執行

jvm基本結構

可能通過上面的描述,大家對JVM運行流程有了一個粗略的認識,那么JVM內部到底是怎么執行一個class文件的呢?

graph TD Class文件-->類加載器 類加載器-->內存空間 內存空間--運行時常量池-->方法區 方法區-->垃圾回收GC 內存空間--對象存儲-->java堆 java堆-->垃圾回收GC 內存空間--局部變量表_棧幀_操作數-->java棧 java棧--線程結束自動釋放-->線程私有 內存空間--本地方法庫_C語言-->本地方法棧 本地方法棧-->線程私有 內存空間--JNI直接操作-->堆外內存

jvm內存分類介紹

JVM內存空間包含:方法區、java堆、java棧、本地方法棧。

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

  2. java堆也是線程共享的區域,我們的類的實例就放在這個區域,可以想象你的一個系統會產生很多實例,因此java堆的空間也是最大的。如果java堆空間不足了,程序會拋出OutOfMemoryError異常。

  3. java棧是每個線程私有的區域,它的生命周期與線程相同,一個線程對應一個java棧,每執行一個方法就會往棧中壓入一個元素,這個元素叫“棧幀”,而棧幀中包括了方法中的局部變量、用於存放中間狀態值的操作棧,如果java棧空間不足了,程序會拋出StackOverflowError異常.

每個幀代表一個方法,Java方法有兩種返回方式,return和拋出異常,兩種方式都會導致該方法對應的幀出棧和釋放內存。

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

  2. PC寄存器(程序計數器),說到這里我們的類已經加載了,實例對象、方法、靜態變量都去了自己改去的地方,那么問題來了,程序該怎么執行,哪個方法先執行,哪個方法后執行,這些指令執行的順序就是PC寄存器在管,它的作用就是控制程序指令的執行順序。

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

  • 靜態變量+常量+類信息+運行時常量池存在方法區中,實例變量存在堆內存中。
  • 基本類型的變量和對象的引用變量都是在函數的棧內存中分


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM