1、 什么是JVM瘩燥?(虛擬機內(nèi)存模型中定義的訪問操作與物理計算機處理的基本一致服猪!)
JVM是Java
VirtualMachine(Java虛擬機)的縮寫彬犯,JVM是一種用于計算設(shè)備的規(guī)范,它是一個虛構(gòu)出來的計算機田炭,是通過在實際的計算機上仿真模擬各種計算機功能來實現(xiàn)的师抄。Java虛擬機包括一套字節(jié)碼指令集、一組寄存器教硫、一個棧叨吮、一個垃圾回收堆和一個存儲方法域辆布。
JVM屏蔽了與具體操作系統(tǒng)平臺相關(guān)的信息,使Java程序只需生成在Java虛擬機上運行的目標代碼(字節(jié)碼),就可以在多種平臺上不加修改地運行茶鉴。JVM在執(zhí)行字節(jié)碼時锋玲,實際上最終還是把字節(jié)碼解釋成具體平臺上的機器指令執(zhí)行。
Java語言的一個非常重要的特點就是與平臺的無關(guān)性蛤铜。而使用Java虛擬機是實現(xiàn)這一特點的關(guān)鍵嫩絮。一般的高級語言如果要在不同的平臺上運行,至少需要編譯成不同的目標代碼围肥。而引入Java語言虛擬機后剿干,Java語言在不同平臺上運行時不需要重新編譯。Java語言使用Java虛擬機屏蔽了與具體平臺相關(guān)的信息穆刻,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節(jié)碼)置尔,就可以在多種平臺上不加修改地運行。Java虛擬機在執(zhí)行字節(jié)碼時氢伟,把字節(jié)碼解釋成具體平臺上的機器指令執(zhí)行榜轿。這就是Java的能夠“一次編譯,到處運行”的原因朵锣。
2谬盐、JRE/JDK/JVM是什么關(guān)系?
JRE(JavaRuntimeEnvironment诚些,Java運行環(huán)境)飞傀,也就是Java平臺。所有的Java 程序都要在JRE下才能運行诬烹。普通用戶只需要運行已開發(fā)好的java程序砸烦,安裝JRE即可。
JDK(Java
Development
Kit)是程序開發(fā)者用來來編譯绞吁、調(diào)試java程序用的開發(fā)工具包幢痘。JDK的工具也是Java程序,也需要JRE才能運行家破。為了保持JDK的獨立性和完整性颜说,在JDK的安裝過程中,JRE也是
安裝的一部分汰聋。所以脑沿,在JDK的安裝目錄下有一個名為jre的目錄,用于存放JRE文件马僻。
JVM(JavaVirtualMachine庄拇,Java虛擬機)是JRE的一部分。它是一個虛構(gòu)出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現(xiàn)的措近。JVM有自己完善的硬件架構(gòu)溶弟,如處理器、堆棧瞭郑、寄存器等辜御,還具有相應(yīng)的指令系統(tǒng)。Java語言最重要的特點就是跨平臺運行屈张。使用JVM就是為了支持與操作系統(tǒng)無關(guān)擒权,實現(xiàn)跨平臺。
3阁谆、Java編譯器只要面向JVM碳抄,生成JVM能理解的代碼或字節(jié)碼文件。Java源文件經(jīng)編譯成字節(jié)碼程序场绿,通過JVM將每一條指令翻譯成不同平臺機器碼剖效,通過特定平臺運行。原理下圖:
jvm原理
4焰盗、jvm的體系結(jié)構(gòu)
(1)java棧內(nèi)存璧尸,它等價于C語言中的棧, 棧的內(nèi)存地址是不連續(xù)的熬拒, 每個線程都擁有自己的棧爷光。 棧里面存儲著的是StackFrame,在《JVM Specification》中文版中被譯作java虛擬機框架澎粟,也叫做棧幀瞎颗。StackFrame包含三類信息:局部變量,執(zhí)行環(huán)境捌议,操作數(shù)棧。局部變量用來存儲一個類的方法中所用到的局部變量引有。執(zhí)行環(huán)境用于保存解析器對于java字節(jié)碼進行解釋過程中需要的信息瓣颅,包括:上次調(diào)用的方法、局部變量指針和 操作數(shù)棧的棧頂和棧底指針譬正。操作數(shù)棧用于存儲運算所需要的操作數(shù)和結(jié)果宫补。StackFrame在方法被調(diào)用時創(chuàng)建,在某個線程中曾我,某個時間點上粉怕,只有一個 框架是活躍的,該框架被稱為Current Frame抒巢,而框架中的方法被稱為Current Method贫贝,其中定義的類為Current Class。局部變量和操作數(shù)棧上的操作總是引用當前框架。當Stack Frame中方法被執(zhí)行完之后稚晚,或者調(diào)用別的StackFrame中的方法時崇堵,則當前棧變?yōu)榱硗庖粋€StackFrame。Stack的大小是由兩種類 型客燕,固定和動態(tài)的鸳劳,動態(tài)類型的棧可以按照線程的需要分配也搓。 下面兩張圖是關(guān)于棧之間關(guān)系以及棧和非堆內(nèi)存的關(guān)系基本描述(來自http://www.programering.com/a/MzM3QzNwATA.html):
(2)Java堆是用來存放對象信息的赏廓,和Stack不同,Stack代表著一種運行時的狀態(tài)傍妒。換句話說幔摸,棧是運行時單位,解決程序該如何執(zhí)行的問題拍顷,而堆是存儲的單位抚太, 解決數(shù)據(jù)存儲的問題。Heap是伴隨著JVM的啟動而創(chuàng)建昔案,負責(zé)存儲所有對象實例和數(shù)組的尿贫。堆的存儲空間和棧一樣是不需要連續(xù)的。
(3)程序計數(shù)寄存器踏揣,程序計數(shù)器(Program Counter Register)是一塊較小的內(nèi)存空間庆亡,它的作用可以看做是當前線程所執(zhí)行的字節(jié)碼的行號指示器。在虛擬機的概念模型里(僅是概念模型捞稿,各種虛擬機可能會通過一些更高效的方式去實現(xiàn))又谋,字節(jié)碼解釋器工作時就是通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令,分支娱局、循環(huán)彰亥、跳轉(zhuǎn)、異常處理衰齐、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個計數(shù)器來完成任斋。
由于Java
虛擬機的多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式來實現(xiàn)的,在任何一個確定的時刻耻涛,一個處理器(對于多核處理器來說是一個內(nèi)核)只會執(zhí)行一條線程中的指令废酷。因此,為了線程切換后能恢復(fù)到正確的執(zhí)行位置抹缕,每條線程都需要有一個獨立的程序計數(shù)器澈蟆,各條線程之間的計數(shù)器互不影響,獨立存儲卓研,我們稱這類內(nèi)存區(qū)域為“線程私有”的內(nèi)存趴俘。如果線程正在執(zhí)行的是一個Java
方法,這個計數(shù)器記錄的是正在執(zhí)行的虛擬機字節(jié)碼指令的地址;如果正在執(zhí)行的是Natvie
方法哮幢,這個計數(shù)器值則為空(Undefined)带膀。此內(nèi)存區(qū)域是唯一一個在Java 虛擬機規(guī)范中沒有規(guī)定任何OutOfMemoryError
情況的區(qū)域。
(4)方法區(qū)域(Method Area)橙垢,在Sun JDK中這塊區(qū)域?qū)?yīng)的為PermanetGeneration垛叨,又稱為持久代。方法區(qū)域存放了所加載的類的信息(名稱柜某、修飾符等)嗽元、類中的靜態(tài)變量、類中定義為final類型的常量喂击、類中的Field信息剂癌、類中的方法信息,當開發(fā)人員在程序中通過Class對象中的getName翰绊、isInterface等方法來獲取信息時佩谷,這些數(shù)據(jù)都來源于方法區(qū)域,同時方法區(qū)域也是全局共享的监嗜,在一定的條件下它也會被GC谐檀,當方法區(qū)域需要使用的內(nèi)存超過其允許的大小時,會拋出OutOfMemory的錯誤信息裁奇。
(5)運行時常量池(Runtime Constant Pool)桐猬,存放的為類中的固定的常量信息、方法和Field的引用信息等刽肠,其空間從方法區(qū)域中分配溃肪。
(6)本地方法堆棧(Native Method Stacks),JVM采用本地方法堆棧來支持native方法的執(zhí)行音五,此區(qū)域用于存儲每個native方法調(diào)用的狀態(tài)惫撰。