一、Java平臺結構圖
二、JVM、JRE和JDK關系
JVM:Java Virtual Machine(Java虛擬機),負責執行符合規范的Class文件
JRE: Java Runtime Environment (java運行環境),包含JVM和類庫
JDK: Java? Development Kit(java開發工具包),包含JRE和開發工具包,例如javac、javah
三、JVM所處的位置
? ? ? ?我們通常工作中所接觸的基本是Java庫和應用以及Java核心類庫,知曉如何使用就可以了,但是歸根結底代碼都是要編譯成class文件由Java虛擬機執行的,所產生的結果或者現象都可以通過Java虛擬機的運行機制來解釋。一些相同的代碼會由于虛擬機的實現不同而產生不同結果。
四、Class文件格式
? ? ? ?編譯后被Java虛擬機所執行的代碼使用了一種平臺中立(不依賴于特定硬件及操作系統的)的二進制格式來表示,并且經常(但并非絕對)以文件的形式存儲,因此這種格式被稱為Class文件格式。Class文件格式中精確地定義了類與接口的表示形式,包括在平臺相關的目標文件格式中一些細節上的慣例,例如字節序(Byte Ordering)等。
? ? ? ?正如概念所說,Java為了能夠實現平臺無關性,制定了一套自己的二進制格式,并經常以文件的方式存儲,稱為Class文件。這樣在不同平臺上,只要都安裝了Java虛擬機,那么都可以運行相同的Class文件。
五、數據類型
? ? ? ?與Java程序語言中的數據類型相似,Java虛擬機可以操作的數據類型可分為兩類:原始類型(Primitive Types,也經常翻譯為原生類型或者基本類型)和引用類型(Reference Types)。與之對應,也存在有原始值(Primitive Values)和引用值(Reference Values)兩種類型的數值可用于變量賦值、參數傳遞、方法返回和運算操作。
基本類型和引用類型的具體情況見下圖:
? ? ? ?Java虛擬機希望更多的類型檢查放在編譯期就完成,在運行期不需要進行這些操作。其中基本類型達到了這樣的要求,在運行期間不需要對其進行類型檢查,也不用和引用類型區分開。這是通過虛擬機的字節碼指令完成的,不同類型的字節碼指令中都包含了相應的數據類型。
整形類型和整型值的取值范圍如下:
? ? byte類型,取值范圍是從-128至127(-27至27-1),包括-128和127。
? ? short類型,取值范圍是從?32768至32767(-215至215-1),包括?32768和32767。
? ? int類型,取值范圍是從?2147483648至2147483647(-231至231-1),包括?2147483648和2147483647。
? long類型,取值范圍是從?9223372036854775808至9223372036854775807(-263至263-1),包括?9223372036854775808和9223372036854775807。
? ? char類型,取值范圍是從0至65535,包括0和65535。
浮點類型、取值集合和浮點值:
? ? ? ?浮點類型包含32位單精度的float類型和64位雙精度的double類型兩種,浮點數除了包括正負帶符號可數的數值,還包括了正負零、正負無窮大和一個特殊的“非數字”標識(Not-a-Number,下文用NaN表示)。NaN值用于表示某些無效的運算操作,例如除數為零等情況。所有Java虛擬機的實現都必須支持兩種標準的浮點數值集合:單精度浮點數集合和雙精度浮點數集合。
returnAddress類型和值:
? ? ? ?returnAddress類型會被Java虛擬機的jsr、ret和jsr_w指令所使用。returnAddress類型的值指向一條虛擬機指令的操作碼。與前面介紹的那些數值類的原始類型不同,returnAddress類型在Java語言之中并不存在相應的類型,也無法在程序運行期間更改returnAddress類型的值。
boolean類型:
? ? ? ?Java虛擬機不提供操作boolean類型的字節碼指令,程序在編譯后boolean類型都轉化成了int操作。但是Java虛擬機支持boolean類型的數組的訪問和修改,共用byte類型數組的字節碼指令。
六、運行時數據區
? ? ? ?Java虛擬機定義了若干種程序運行期間會使用到的運行時數據區,其中有一些會隨著虛擬機啟動而創建,隨著虛擬機退出而銷毀。另外一些則是與線程一一對應的,這些與線程對應的數據區域會隨著線程開始和結束而創建和銷毀。
Java虛擬機的邏輯構成
? ? ? ?可以看出Java虛擬機的運行時數據區包括了:方法區、Java堆、Java虛擬機棧、PC寄存器、本地方法棧。
方法區
? ? ? ?方法區在虛擬機啟動的時候被創建,它存儲了每一個類的結構信息,例如運行時常量池、字段和方法數據、構造函數和普通方法的字節碼內容、還包括一些在類、實例、接口初始化時用到的特殊方法。?
方法區可能發生如下異常情況:?
? ? ? ?如果方法區的內存空間不能滿足內存分配請求,那Java虛擬機將拋出一個OutOfMemoryError異常.?
運行時常量池:?
? ? ? ?運行時常量池(Runtime Constant Pool)是每一個類或接口的常量池的運行時表示形式,它包括了若干種不同的常量:從編譯期可知的數值字面量到必須運行期解析后才能獲得的方法或字段引用。運行時常量池在方法區中。
在創建類和接口的運行時常量池時,可能會發生如下異常情況:
? ? ? ?當創建類或接口的時候,如果構造運行時常量池所需要的內存空間超過了方法區所能提供的最大值,那Java虛擬機將會拋出一個OutOfMemoryError異常。
Java堆
? ? ? ?Java堆在虛擬機啟動的時候被創建,Java堆主要用來為類實例對象和數組分配內存。Java虛擬機規范并沒有規定對象在堆中的形式。
Java堆可能發生如下異常情況:
? ? ? ?如果實際所需的堆超過了自動內存管理系統能提供的最大容量,那Java虛擬機將會拋出一個OutOfMemoryError異常。
Java虛擬機棧
? ? ? ?每個Java虛擬機線程都有自己的Java虛擬機棧。Java虛擬機棧用來存放棧幀,而棧幀主要包括了:局部變量表、操作數棧、動態鏈接。
? ? ? ?Java虛擬機使用局部變量表來完成方法調用時的參數傳遞。局部變量表的長度在編譯期已經決定了并存儲于類和接口的二進制表示中,一個局部變量可以保存一個類型為boolean、byte、char、short、float、reference 和 returnAddress的數據,兩個局部變量可以保存一個類型為long和double的數據。
? ? ? ?Java虛擬機提供一些字節碼指令來從局部變量表或者對象實例的字段中復制常量或變量值到操作數棧中,也提供了一些指令用于從操作數棧取走數據、操作數據和把操作結果重新入棧。在方法調用的時候,操作數棧也用來準備調用方法的參數以及接收方法返回結果。
? ? ? ?每個棧幀中都包含一個指向運行時常量區的引用支持當前方法的動態鏈接。在Class文件中,方法調用和訪問成員變量都是通過符號引用來表示的,動態鏈接的作用就是將符號引用轉化為實際方法的直接引用或者訪問變量的運行是內存位置的正確偏移量。?
? ? ? ?總的來說,Java虛擬機棧是用來存放局部變量和過程結果的地方。?
Java虛擬機棧可能發生如下異常情況:?
? ? ? ?如果線程請求分配的棧容量超過Java虛擬機棧允許的最大容量時,Java虛擬機將會拋出一個StackOverflowError異常。?
? ? ? ?如果Java虛擬機棧可以動態擴展,并且擴展的動作已經嘗試過,但是目前無法申請到足夠的內存去完成擴展,或者在建立新的線程時沒有足夠的內存去創建對應的虛擬機棧,那Java虛擬機將會拋出一個OutOfMemoryError異常。
PC寄存器
? ? ? ?每個Java虛擬機線程都有自己的PC寄存器。在某個線程被新建時,會獲得一個PC寄存器。線程當前執行的方法稱為當前方法,PC寄存器用來存放當前方法中當前執行的字節碼指令的地址,如果當前方法是本地方法(Native),那么寄存器存放undefined。寄存器的大小至少應該能夠存放一個returnAddress類型的數據或者與平臺相關的本地指針的值。
本地方法棧
? ? ? ?本地方法棧用于支持native方法的運行。