JVM:Java Virtual Machine(Java虛擬機(jī)),負(fù)責(zé)執(zhí)行符合規(guī)范的Class文件
JRE:Java Runtime Environment(java運(yùn)行環(huán)境),包含JVM和類庫
JDK:Java Development Kit(java開發(fā)工具包),包含JRE和開發(fā)工具包,例如javac、javah
相關(guān)文章:http://blog.csdn.net/ljheee/article/details/50810570
(1)通常工作中所接觸的基本是Java庫和應(yīng)用以及Java核心類庫,知道如何使用就可以了,但是歸根結(jié)底代碼都是要編譯成class文件由Java虛擬機(jī)裝載執(zhí)行,所產(chǎn)生的結(jié)果或者現(xiàn)象都可以通過Java虛擬機(jī)的運(yùn)行機(jī)制來解釋。一些相同的代碼會由于虛擬機(jī)的實(shí)現(xiàn)不同而產(chǎn)生不同結(jié)果。
(2)在Java平臺的結(jié)構(gòu)中,可以看出,Java虛擬機(jī)(JVM)處在核心的位置,是程序與底層操作系統(tǒng)和硬件無關(guān)的關(guān)鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統(tǒng),其中依賴于平臺的部分稱為適配器;JVM通過移植接口在具體的平臺和操作系統(tǒng)上實(shí)現(xiàn);在JVM的上方是Java的基本類庫和擴(kuò)展類庫以及它們的API, 利用Java API編寫的應(yīng)用程序(application)和小程序(Java applet)可以在任何Java平臺上運(yùn)行而無需考慮底層平臺,就是因?yàn)橛蠮ava虛擬機(jī)(JVM)實(shí)現(xiàn)了程序與操作系統(tǒng)的分離,從而實(shí)現(xiàn)了Java的平臺無關(guān)性。
(3)對JVM規(guī)范的的抽象說明是一些概念的集合,它們已經(jīng)在書《The Java Virtual Machine Specification》(《Java虛擬機(jī)規(guī)范》)中被詳細(xì)地描述了;對JVM的具體實(shí)現(xiàn)要么是軟件,要么是軟件和硬件的組合,它已經(jīng)被許多生產(chǎn)廠商所實(shí)現(xiàn),并存在于多種平臺之上;運(yùn)行Java程序的任務(wù)由JVM的運(yùn)行期實(shí)例單個承擔(dān)。
(4)JVM可以由不同的廠商來實(shí)現(xiàn)。由于廠商的不同必然導(dǎo)致JVM在實(shí)現(xiàn)上的一些不同,像國內(nèi)就有著名的TaobaoVM;然而JVM還是可以實(shí)現(xiàn)跨平臺的特性,這就要?dú)w功于設(shè)計(jì)JVM時的體系結(jié)構(gòu)了。
(5)JVM在它的生存周期中有一個明確的任務(wù),那就是裝載字節(jié)碼文件,一旦字節(jié)碼進(jìn)入虛擬機(jī),它就會被解釋器解釋執(zhí)行,或者是被即時代碼發(fā)生器有選擇的轉(zhuǎn)換成機(jī)器碼執(zhí)行,即Java程序被執(zhí)行。因此當(dāng)Java程序啟動的時候,就產(chǎn)生JVM的一個實(shí)例;當(dāng)程序運(yùn)行結(jié)束的時候,該實(shí)例也跟著消失了。
編譯后被Java虛擬機(jī)所執(zhí)行的代碼使用了一種平臺中立(不依賴于特定硬件及操作系統(tǒng)的)的二進(jìn)制格式來表示,并且經(jīng)常(但并非絕對)以文件的形式存儲,因此這種格式被稱為Class文件格式。Class文件格式中精確地定義了類與接口的表示形式,包括在平臺相關(guān)的目標(biāo)文件格式中一些細(xì)節(jié)上的慣例,
正如概念所說,Java為了能夠?qū)崿F(xiàn)平臺無關(guān)性,制定了一套自己的二進(jìn)制格式,并經(jīng)常以文件的方式存儲,稱為Class文件。這樣在不同平臺上,只要都安裝了Java虛擬機(jī),具備Java運(yùn)行環(huán)境[JRE],那么都可以運(yùn)行相同的Class文件。
上圖描述了Java程序運(yùn)行的一個全過程,也可以看出Java平臺由Java虛擬機(jī)和Java應(yīng)用程序接口搭建,Java語言則是進(jìn)入這個平臺的通道,用Java語言編寫并編譯的程序可以運(yùn)行在這個平臺上。
由Java源文件編譯生成字節(jié)碼文件,這個過程非常復(fù)雜,學(xué)過《編譯原理》的朋友都知道必須經(jīng)過詞法分析、語法分析、語義分析、中間代碼生成、代碼優(yōu)化等;同樣的,Java源文件到字節(jié)碼的生成也想要經(jīng)歷這些步驟。Javac編譯器的最后任務(wù)就是調(diào)用con.sun.tools.javac.jvm.Gen類將這課語法樹編譯為Java字節(jié)碼文件。
其實(shí),所謂的編譯字節(jié)碼,無非就是將符合Java語法規(guī)范的Java代碼轉(zhuǎn)化為符合JVM規(guī)范的字節(jié)碼文件。JVM的架構(gòu)模型是基于棧的,大部分都需要通過棧來完成。
字節(jié)碼結(jié)構(gòu)比較特殊,其內(nèi)部不包含任何的分隔符,無法人工區(qū)分段落(字節(jié)碼文件本身就是給機(jī)器讀的),所以無論是字節(jié)順序、數(shù)量都是有嚴(yán)格規(guī)定的,所有16位、32位、64位長度的數(shù)據(jù)都將構(gòu)造成2個、4個、8個-----8位字節(jié)單位來表示,多字節(jié)數(shù)據(jù)項(xiàng)總是按照Big-endian順序(高位字節(jié)在地址的最低位,地位字節(jié)在地址的最高位)來進(jìn)行存儲。
參考《Java虛擬機(jī)規(guī)范 Java SE7版》的描述,每一個字節(jié)碼其實(shí)都對應(yīng)著全局唯一的一個類或者接口的定義信息。字節(jié)碼文件才用的是一種類似于C語言結(jié)構(gòu)體的偽結(jié)構(gòu)來描述字節(jié)碼文件格式。字節(jié)碼文件中對應(yīng)的“基本類型”u1,u2,u4,u8分別表示無符號1、2、4、8個字節(jié)。
Class文件----總體格式
值得一提的是,一個有效的class字節(jié)碼文件的前4個字節(jié)為0xCAFEBABE,都是固定的,被稱為“魔術(shù)”,即magic。它就是JVM用于校驗(yàn)所讀取的目標(biāo)文件是否是一個有效且合法的字節(jié)碼文件。由此可見,JVM并不是通過判斷文件后綴名的方式來校驗(yàn),以防止人為手動修改。
一個JVM實(shí)例的行為不光是它自己的事,還涉及到它的子系統(tǒng)、存儲區(qū)域、數(shù)據(jù)類型和指令這些部分,它們描述了JVM的一個抽象的內(nèi)部體系結(jié)構(gòu),其目的不光規(guī)定實(shí)現(xiàn)JVM時它內(nèi)部的體系結(jié)構(gòu),更重要的是提供了一種方式,用于嚴(yán)格定義實(shí)現(xiàn)時的外部行為。每個JVM都有兩種機(jī)制,一個是裝載具有合適名稱的類(類或是接口),叫做類裝載子系統(tǒng);另外的一個負(fù)責(zé)執(zhí)行包含在已裝載的類或接口中的指令,叫做運(yùn)行引擎。每個JVM又包括方法區(qū)、堆、Java棧、程序計(jì)數(shù)器和本地方法棧這五個部分,這幾個部分和類裝載機(jī)制與運(yùn)行引擎機(jī)制一起組成的體系結(jié)構(gòu)圖為:
Java虛擬機(jī)定義了若干種程序運(yùn)行期間會使用到的運(yùn)行時數(shù)據(jù)區(qū),其中有一些會隨著虛擬機(jī)啟動而創(chuàng)建,隨著虛擬機(jī)退出而銷毀。另外一些則是與線程一一對應(yīng)的,這些與線程對應(yīng)的數(shù)據(jù)區(qū)域會隨著線程開始和結(jié)束而創(chuàng)建和銷毀。
可以看出Java虛擬機(jī)的運(yùn)行時數(shù)據(jù)區(qū)包括了:方法區(qū)、Java堆、Java虛擬機(jī)棧、PC寄存器、本地方法棧,還有常量池。它們被分為兩大類-----線程共享、私有數(shù)據(jù)區(qū)。
包括:Java堆、方法區(qū)、常量池。它們會隨著虛擬機(jī)啟動而創(chuàng)建,隨著虛擬機(jī)退出而銷毀。
推薦文章:http://blog.csdn.net/ljheee/article/details/52196455
Java堆在虛擬機(jī)啟動的時候被創(chuàng)建,Java堆主要用來為類實(shí)例對象和數(shù)組分配內(nèi)存。Java虛擬機(jī)規(guī)范并沒有規(guī)定對象在堆中的形式。
分代收集算法:采用不同算法處理[存放和回收]Java瞬時對象和長久對象。大部分Java對象都是瞬時對象,朝生夕滅,存活很短暫,通常存放在Young新生代,采用復(fù)制算法對新生代進(jìn)行垃圾回收。老年代對象的生命周期一般都比較長,極端情況下會和JVM生命周期保持一致;通常采用標(biāo)記-壓縮算法對老年代進(jìn)行垃圾回收。
方法區(qū)在虛擬機(jī)啟動的時候被創(chuàng)建,它存儲了每一個類的結(jié)構(gòu)信息,例如運(yùn)行時常量池、字段和方法數(shù)據(jù)、構(gòu)造函數(shù)和普通方法的字節(jié)碼內(nèi)容、還包括在類、實(shí)例、接口初始化時用到的特殊方法。
方法區(qū)可能發(fā)生如下異常情況: 如果方法區(qū)的內(nèi)存空間不能滿足內(nèi)存分配請求,那Java虛擬機(jī)將拋出一個OutOfMemoryError異常.
運(yùn)行時常量池(Runtime Constant Pool)是每一個類或接口的常量池的運(yùn)行時表示形式,它包括了若干種不同的常量:從編譯期可知的數(shù)值字面量到必須運(yùn)行期解析后才能獲得的方法或字段引用。運(yùn)行時常量池在方法區(qū)中。
在創(chuàng)建類和接口的運(yùn)行時常量池時,可能會發(fā)生如下異常情況:當(dāng)創(chuàng)建類或接口的時候,如果構(gòu)造運(yùn)行時常量池所需要的內(nèi)存空間超過了方法區(qū)所能提供的最大值,那Java虛擬機(jī)將會拋出一個OutOfMemoryError異常。
包括:PC寄存器、JVM棧、本地方法區(qū)。它們是與線程一一對應(yīng)的,這些與線程對應(yīng)的數(shù)據(jù)區(qū)域會隨著線程開始和結(jié)束而創(chuàng)建和銷毀。
每個Java虛擬機(jī)線程都有自己的PC寄存器。在某個線程被新建時,會獲得一個PC寄存器。線程當(dāng)前執(zhí)行的方法稱為當(dāng)前方法,PC寄存器用來存放當(dāng)前方法中當(dāng)前執(zhí)行的字節(jié)碼指令的地址;之所以為每一個線程都分配一個PC寄存器,試想:多線程運(yùn)行時,某個時間片內(nèi)只執(zhí)行一個線程,CPU在不停的切換多個線程,那如何記錄具體每一個線程上一次執(zhí)行到哪個位置了呢,這時候PC寄存器用來存放當(dāng)前方法中當(dāng)前執(zhí)行的字節(jié)碼指令的地址,就完美解決了,這就是為什么PC寄存器是線程私有數(shù)據(jù)區(qū)的原因。
如果當(dāng)前方法是本地方法(Native),那么寄存器存放undefined。寄存器的大小至少應(yīng)該能夠存放一個returnAddress類型的數(shù)據(jù)或者與平臺相關(guān)的本地指針的值。
PC寄存器是惟一一個沒有明確規(guī)定需要拋出OutOfMemoryError異常的運(yùn)行時數(shù)據(jù)區(qū)。
每個Java虛擬機(jī)線程都有自己的Java虛擬機(jī)棧。Java虛擬機(jī)棧用來存放棧幀,而棧幀主要包括了:局部變量表、操作數(shù)棧、動態(tài)鏈接。Java虛擬機(jī)棧允許被實(shí)現(xiàn)為固定大小或者可動態(tài)擴(kuò)展的內(nèi)存大小。
Java虛擬機(jī)使用局部變量表來完成方法調(diào)用時的參數(shù)傳遞。局部變量表的長度在編譯期已經(jīng)決定了并存儲于類和接口的二進(jìn)制表示中,一個局部變量可以保存一個類型為boolean、byte、char、short、float、reference和returnAddress的數(shù)據(jù),兩個局部變量可以保存一個類型為long和double的數(shù)據(jù)。
Java虛擬機(jī)提供一些字節(jié)碼指令來從局部變量表或者對象實(shí)例的字段中復(fù)制常量或變量值到操作數(shù)棧中,也提供了一些指令用于從操作數(shù)棧取走數(shù)據(jù)、操作數(shù)據(jù)和把操作結(jié)果重新入棧。在方法調(diào)用的時候,操作數(shù)棧也用來準(zhǔn)備調(diào)用方法的參數(shù)以及接收方法返回結(jié)果。
每個棧幀中都包含一個指向運(yùn)行時常量區(qū)的引用支持當(dāng)前方法的動態(tài)鏈接。在Class文件中,方法調(diào)用和訪問成員變量都是通過符號引用來表示的,動態(tài)鏈接的作用就是將符號引用轉(zhuǎn)化為實(shí)際方法的直接引用或者訪問變量的運(yùn)行是內(nèi)存位置的正確偏移量。
總的來說,Java虛擬機(jī)棧是用來存放局部變量和過程結(jié)果的地方。
Java虛擬機(jī)??赡馨l(fā)生如下異常情況: 如果Java虛擬機(jī)棧被實(shí)現(xiàn)為固定大小內(nèi)存,線程請求分配的棧容量超過Java虛擬機(jī)棧允許的最大容量時,Java虛擬機(jī)將會拋出一個StackOverflowError異常。
如果Java虛擬機(jī)棧被實(shí)現(xiàn)為動態(tài)擴(kuò)展內(nèi)存大小,并且擴(kuò)展的動作已經(jīng)嘗試過,但是目前無法申請到足夠的內(nèi)存去完成擴(kuò)展,或者在建立新的線程時沒有足夠的內(nèi)存去創(chuàng)建對應(yīng)的虛擬機(jī)棧,那Java虛擬機(jī)將會拋出一個OutOfMemoryError異常。
本地方法棧用于支持native方法的運(yùn)行。(native方法,比如用C/C++實(shí)現(xiàn)的代碼)