Java虛擬機規範----JVM體系結構

1、Java平臺的結構圖

 

2、JVM與JRE、JDK關係?

  JVM:Java Virtual Machine(Java虛擬機),負責執行符合規範的Class文件java

  JRE:Java Runtime Environment(java運行環境),包含JVM和類庫算法

        JDK:Java  Development Kit(java開發工具包),包含JRE和開發工具包,例如javac、javah小程序

相關文章:http://blog.csdn.net/ljheee/article/details/50810570數組

 

3、JVM所處的位置

 

(1)一般工做中所接觸的基本是Java庫和應用以及Java核心類庫,知道如何使用就能夠了,可是歸根結底代碼都是要編譯成class文件由Java虛擬機裝載執行,所產生的結果或者現象均可以經過Java虛擬機的運行機制來解釋。一些相同的代碼會因爲虛擬機的實現不一樣而產生不一樣結果。多線程

(2)在Java平臺的結構中,能夠看出,Java虛擬機(JVM)處在覈心的位置,是程序與底層操做系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操做系統,其中依賴於平臺的部分稱爲適配器;JVM經過移植接口在具體的平臺和操做系統上實現;在JVM的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application)和小程序(Java applet)能夠在任何Java平臺上運行而無需考慮底層平臺,就是由於有Java虛擬機(JVM)實現了程序與操做系統的分離,從而實現了Java的平臺無關性。架構

(3)對JVM規範的的抽象說明是一些概念的集合,它們已經在書《The Java Virtual Machine Specification》(《Java虛擬機規範》)中被詳細地描述了;對JVM的具體實現要麼是軟件,要麼是軟件和硬件的組合,它已經被許多生產廠商所實現,並存在於多種平臺之上;運行Java程序的任務由JVM的運行期實例單個承擔。app

(4)JVM能夠由不一樣的廠商來實現。因爲廠商的不一樣必然致使JVM在實現上的一些不一樣,像國內就有著名的TaobaoVM;然而JVM仍是能夠實現跨平臺的特性,這就要歸功於設計JVM時的體系結構了。jvm

(5)JVM在它的生存週期中有一個明確的任務,那就是裝載字節碼文件,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行,即Java程序被執行。所以當Java程序啓動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟着消失了。函數

 4、Class字節碼

    編譯後被Java虛擬機所執行的代碼使用了一種平臺中立(不依賴於特定硬件及操做系統的)的二進制格式來表示,而且常常(但並不是絕對)以文件的形式存儲,所以這種格式被稱爲Class文件格式。Class文件格式中精確地定義了類與接口的表示形式,包括在平臺相關的目標文件格式中一些細節上的慣例,工具

正如概念所說,Java爲了可以實現平臺無關性,制定了一套本身的二進制格式,並常常以文件的方式存儲,稱爲Class文件。這樣在不一樣平臺上,只要都安裝了Java虛擬機,具有Java運行環境[JRE],那麼均可以運行相同的Class文件。

上圖描述了Java程序運行的一個全過程,也能夠看出Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序能夠運行在這個平臺上。

 

       由Java源文件編譯生成字節碼文件,這個過程很是複雜,學過《編譯原理》的朋友都知道必須通過詞法分析、語法分析、語義分析、中間代碼生成、代碼優化等;一樣的,Java源文件到字節碼的生成也想要經歷這些步驟。Javac編譯器的最後任務就是調用con.sun.tools.javac.jvm.Gen類將這課語法樹編譯爲Java字節碼文件。

       其實,所謂的編譯字節碼,無非就是將符合Java語法規範的Java代碼轉化爲符合JVM規範的字節碼文件。JVM的架構模型是基於棧的,大部分都須要經過棧來完成。

       字節碼結構比較特殊,其內部不包含任何的分隔符,沒法人工區分段落(字節碼文件自己就是給機器讀的),因此不管是字節順序、數量都是有嚴格規定的,全部16位、32位、64位長度的數據都將構形成2個、4個、8個-----8位字節單位來表示,多字節數據項老是按照Big-endian順序(高位字節在地址的最低位,地位字節在地址的最高位)來進行存儲。

       參考《Java虛擬機規範  Java SE7版》的描述,每個字節碼其實都對應着全局惟一的一個類或者接口的定義信息。字節碼文件才用的是一種相似於C語言結構體的僞結構來描述字節碼文件格式。字節碼文件中對應的「基本類型」u1,u2,u4,u8分別表示無符號一、二、四、8個字節。

Class文件----整體格式

       值得一提的是,一個有效的class字節碼文件的前4個字節爲0xCAFEBABE,都是固定的,被稱爲「魔術」,即magic。它就是JVM用於校驗所讀取的目標文件是不是一個有效且合法的字節碼文件。因而可知,JVM並非經過判斷文件後綴名的方式來校驗,以防止人爲手動修改。

5、Java虛擬機的體系結構

      一個JVM實例的行爲不光是它本身的事,還涉及到它的子系統、存儲區域、數據類型和指令這些部分,它們描述了JVM的一個抽象的內部體系結構,其目的不光規定實現JVM時它內部的體系結構,更重要的是提供了一種方式,用於嚴格定義實現時的外部行爲。每一個JVM都有兩種機制,一個是裝載具備合適名稱的類(類或是接口),叫作類裝載子系統;另外的一個負責執行包含在已裝載的類或接口中的指令,叫作運行引擎。每一個JVM又包括方法區、堆、Java棧、程序計數器和本地方法棧這五個部分,這幾個部分和類裝載機制與運行引擎機制一塊兒組成的體系結構圖爲:

 

      Java虛擬機定義了若干種程序運行期間會使用到的運行時數據區,其中有一些會隨着虛擬機啓動而建立,隨着虛擬機退出而銷燬。另一些則是與線程一一對應的,這些與線程對應的數據區域會隨着線程開始和結束而建立和銷燬。

能夠看出Java虛擬機的運行時數據區包括了:方法區、Java堆、Java虛擬機棧、PC寄存器、本地方法棧,還有常量池。它們被分爲兩大類-----線程共享、私有數據區。

1.線程共享數據區

包括:Java堆、方法區、常量池。它們會隨着虛擬機啓動而建立,隨着虛擬機退出而銷燬。

(1)Java堆

推薦文章:http://blog.csdn.net/ljheee/article/details/52196455

       Java堆在虛擬機啓動的時候被建立,Java堆主要用來爲類實例對象和數組分配內存。Java虛擬機規範並無規定對象在堆中的形式。

     在Java中,堆被劃分紅兩個不一樣的區域:新生代( Young )、老年代( Old );這也就是JVM採用的「分代收集算法」,簡單說,就是針對不一樣特徵的java對象採用不一樣的策略實施存放和回收,天然所用分配機制和回收算法就不同。新生代( Young ) 又被劃分爲三個區域:Eden、From Survivor、To Survivor。(《Java虛擬機精講》(高翔龍...)) 

       分代收集算法:採用不一樣算法處理[存放和回收]Java瞬時對象和長久對象。大部分Java對象都是瞬時對象,朝生夕滅,存活很短暫,一般存放在Young新生代,採用複製算法對新生代進行垃圾回收。老年代對象的生命週期通常都比較長,極端狀況下會和JVM生命週期保持一致;一般採用標記-壓縮算法對老年代進行垃圾回收。

       這樣劃分的目的是爲了使JVM可以更好的管理堆內存中的對象,包括內存的分配以及回收。

    Java堆可能發生以下異常狀況:若是實際所需的堆超過了自動內存管理系統能提供的最大容量,那Java虛擬機將會拋出一個OutOfMemoryError異常。 

(2)方法區

      方法區在虛擬機啓動的時候被建立,它存儲了每個類的結構信息,例如運行時常量池、字段和方法數據、構造函數和普通方法的字節碼內容、還包括在類、實例、接口初始化時用到的特殊方法。 

      方法區可能發生以下異常狀況: 若是方法區的內存空間不能知足內存分配請求,那Java虛擬機將拋出一個OutOfMemoryError異常. 

(3)常量池

      運行時常量池(Runtime Constant Pool)是每個類或接口的常量池的運行時表示形式,它包括了若干種不一樣的常量:從編譯期可知的數值字面量到必須運行期解析後才能得到的方法或字段引用。運行時常量池在方法區中。

      在建立類和接口的運行時常量池時,可能會發生以下異常狀況:當建立類或接口的時候,若是構造運行時常量池所須要的內存空間超過了方法區所能提供的最大值,那Java虛擬機將會拋出一個OutOfMemoryError異常。

2.線程私有數據區

     包括:PC寄存器、JVM棧、本地方法區。它們是與線程一一對應的,這些與線程對應的數據區域會隨着線程開始和結束而建立和銷燬。

(1)PC寄存器

      每一個Java虛擬機線程都有本身的PC寄存器。在某個線程被新建時,會得到一個PC寄存器。線程當前執行的方法稱爲當前方法,PC寄存器用來存放當前方法中當前執行的字節碼指令的地址;之因此爲每個線程都分配一個PC寄存器,試想:多線程運行時,某個時間片內只執行一個線程,CPU在不停的切換多個線程,那如何記錄具體每個線程上一次執行到哪一個位置了呢,這時候PC寄存器用來存放當前方法中當前執行的字節碼指令的地址,就完美解決了,這就是爲何PC寄存器是線程私有數據區的緣由。

      若是當前方法是本地方法(Native),那麼寄存器存放undefined。寄存器的大小至少應該可以存放一個returnAddress類型的數據或者與平臺相關的本地指針的值。

PC寄存器是唯一一個沒有明確規定須要拋出OutOfMemoryError異常的運行時數據區。

(2)JVM棧

       每一個Java虛擬機線程都有本身的Java虛擬機棧。Java虛擬機棧用來存放棧幀,而棧幀主要包括了:局部變量表、操做數棧、動態連接。Java虛擬機棧容許被實現爲固定大小或者可動態擴展的內存大小。

       Java虛擬機使用局部變量表來完成方法調用時的參數傳遞。局部變量表的長度在編譯期已經決定了並存儲於類和接口的二進制表示中,一個局部變量能夠保存一個類型爲boolean、byte、char、short、float、reference和returnAddress的數據,兩個局部變量能夠保存一個類型爲long和double的數據。

  Java虛擬機提供一些字節碼指令來從局部變量表或者對象實例的字段中複製常量或變量值到操做數棧中,也提供了一些指令用於從操做數棧取走數據、操做數據和把操做結果從新入棧。在方法調用的時候,操做數棧也用來準備調用方法的參數以及接收方法返回結果。

  每一個棧幀中都包含一個指向運行時常量區的引用支持當前方法的動態連接。在Class文件中,方法調用和訪問成員變量都是經過符號引用來表示的,動態連接的做用就是將符號引用轉化爲實際方法的直接引用或者訪問變量的運行是內存位置的正確偏移量。 

        總的來講,Java虛擬機棧是用來存放局部變量和過程結果的地方。 

       Java虛擬機棧可能發生以下異常狀況: 若是Java虛擬機棧被實現爲固定大小內存,線程請求分配的棧容量超過Java虛擬機棧容許的最大容量時,Java虛擬機將會拋出一個StackOverflowError異常。 

       若是Java虛擬機棧被實現爲動態擴展內存大小,而且擴展的動做已經嘗試過,可是目前沒法申請到足夠的內存去完成擴展,或者在創建新的線程時沒有足夠的內存去建立對應的虛擬機棧,那Java虛擬機將會拋出一個OutOfMemoryError異常。 

(3)本地方法區

       本地方法棧用於支持native方法的運行。(native方法,好比用C/C++實現的代碼)

相關文章
相關標籤/搜索