什麼是jvm?jvm是一種用於計算設備的規範,它是一個虛構出來的機器,是經過在實際的計算機上仿真模擬各類功能實現的。它包含一套字節碼指令集,一組寄存器,一個棧,一個垃圾回收堆和一個存儲方法域。JVM屏蔽了與具體操做系統平臺相關的信息,使Java程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就能夠在多種平臺上不加修改地運行。
JVM在執行字節碼時,實際上最終仍是把字節碼解釋成具體平臺上的機器指令執行。
jdk、jre、jvm是什麼關係?
(1)JRE(Java Runtime Environment),也就是java平臺。全部的java程序都要在JRE環境下才能運行。
(2)JDK(Java Development Kit),是開發者用來編譯、調試程序用的開發包。JDK也是JAVA程序須要在JRE上運行。
(3)JVM(Java Virtual Machine),是JRE的一部分。它是一個虛構出來的計算機,是經過在實際的計算機上仿真模擬各類計算機功能來實現的。
JVM有本身完善的硬件架構,如處理器、堆棧、寄存器等,還具備相應的指令系統。
Java語言最重要的特色就是跨平臺運行。使用JVM就是爲了支持與操做系統無關,實現跨平臺。
JVM原理
(1)jvm是java的核心和基礎,在java編譯器和os平臺之間的虛擬處理器,可在上面執行字節碼程序。
(2)java編譯器只要面向jvm,生成jvm能理解的字節碼文件。java源文件經編譯成字節碼程序,經過jvm將每條指令翻譯成不一樣的機器碼,經過特定平臺運行。
JVM執行程序的過程
1) 加載.class文件
2) 管理並分配內存
3) 執行垃圾收集
JRE(java運行時環境)由JVM構造的java程序的運行環,也是Java程序運行的環境,可是他同時一個操做系統的一個應用程序一個進程,所以他也有他本身的運行的生命週期,也有本身的代碼和數據空間。JVM在整個jdk中處於最底層,負責於操做系統的交互,用來屏蔽操做系統環境,提供一個完整的Java運行環境,所以也就虛擬計算機。操做系統裝入JVM是經過jdk中Java.exe來完成,經過下面4步來完成JVM環境:
1) 建立JVM裝載環境和配置
2) 裝載JVM.dll
3) 初始化JVM.dll並掛界到JNIENV(JNI調用接口)實例
4) 調用JNIEnv實例裝載並處理class類
JVM的生命週期
1) JVM實例對應了一個獨立運行的java程序它是進程級別
a) 啓動。啓動一個Java程序時,一個JVM實例就產生了,任何一個擁有public static void
main(String[] args)函數的class均可以做爲JVM實例運行的起點
b) 運行。main()做爲該程序初始線程的起點,任何其餘線程均由該線程啓動。JVM內部有兩種線程:守護線程和非守護線程,main()屬於非守護線程,守護線程一般由JVM本身使用,java程序也能夠代表本身建立的線程是守護線程
c) 消亡。當程序中的全部非守護線程都終止時,JVM才退出;若安全管理器容許,程序也可使用Runtime類或者System.exit()來退出
2) JVM執行引擎實例則對應了屬於用戶運行程序的線程它是線程級別的。
JVM內存模型
a) 程序計數器(PC寄存器)
因爲在JVM中,多線程是經過線程輪流切換來得到CPU執行時間的,所以,在任一具體時刻,一個CPU的內核只會執行一條線程中的指令,所以,爲了可以使得每一個線程都在線程切換後可以恢復在切換以前的程序執行位置,每一個線程都須要有本身獨立的程序計數器,而且不能互相被幹擾,不然就會影響到程序的正常執行次序。所以,能夠這麼說,程序計數器是每一個線程所私有的。因爲程序計數器中存儲的數據所佔空間的大小不會隨程序的執行而發生改變,所以,對於程序計數器是不會發生內存溢出現象(OutOfMemory)的。
b) java棧
Java棧中存放的是一個個的棧幀,每一個棧幀對應一個被調用的方法,在棧幀中包括局部變量表(Local Variables)、操做數棧(Operand Stack)、指向當前方法所屬的類的運行時常量池(運行時常量池的概念在方法區部分會談到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些額外的附加信息。當線程執行一個方法時,就會隨之建立一個對應的棧幀,並將創建的棧幀壓棧。當方法執行完畢以後,便會將棧幀出棧。
c)本地方法棧
本地方法棧與Java棧的做用和原理很是類似。區別只不過是Java棧是爲執行Java方法服務的,而本地方法棧則是爲執行本地方法(Native Method)服務的。
d)堆
Java中的堆是用來存儲對象自己的以及數組(數組引用是存放在Java棧中的)。堆是被全部線程共享的,在JVM中只有一個堆。
e)方法區
與堆同樣,是被線程共享的區域。在方法區中,存儲了每一個類的信息(包括類的名稱、方法信息、字段信息)、靜態變量、常量以及編譯器編譯後的代碼等。
在Class文件中除了類的字段、方法、接口等描述信息外,還有一項信息是常量池,用來存儲編譯期間生成的字面量和符號引用。
在方法區中有一個很是重要的部分就是運行時常量池,它是每個類或接口的常量池的運行時表示形式,在類和接口被加載到JVM後,對應的運行時常量池就被建立出來。固然並不是Class文件常量池中的內容才能進入運行時常量池,在運行期間也可將新的常量放入運行時常量池中,好比String的intern方法。
JVM內存溢出的狀況
a) 程序計數器(Program Counter Register)
每條線程都有一個獨立的的程序計數器,各線程間的計數器互不影響,所以該區域是線程私有的。該內存區域是惟一一個在Java虛擬機規範中沒有規定任何OOM(內存溢出:OutOfMemoryError)狀況的區域。
b)Java虛擬機棧(Java Virtual Machine Stacks)
在Java虛擬機規範中,對這個區域規定了兩種異常狀況:
一、若是線程請求的棧深度大於虛擬機所容許的深度,將拋出StackOverflowError異常。
二、若是虛擬機在動態擴展棧時沒法申請到足夠的內存空間,則拋出OutOfMemoryError異常。
這兩種狀況存在着一些互相重疊的地方:當棧空間沒法繼續分配時,究竟是內存過小,仍是已使用的棧空間太大,其本質上只是對同一件事情的兩種描述而已。
在單線程的操做中,不管是因爲棧幀太大,仍是虛擬機棧空間過小,當棧空間沒法分配時,虛擬機拋出的都是StackOverflowError異常,而不會獲得OutOfMemoryError異常。
而在多線程環境下,則會拋出OutOfMemoryError異常。
c)堆Java Heap
Java Heap是Java虛擬機所管理的內存中最大的一塊,它是全部線程共享的一塊內存區域。幾乎全部的對象實例和數組都在這類分配內存。Java Heap是垃圾收集器管理的主要區域,所以不少時候也被稱爲「GC堆」。
根據Java虛擬機規範的規定,Java堆能夠處在物理上不連續的內存空間中,只要邏輯上是連續的便可。若是在堆中沒有內存可分配時,而且堆也沒法擴展時,將會拋出OutOfMemoryError異常。
d)方法區域,又被稱爲「永久代」,當方法區沒法知足內存分配需求時,將拋出OutOfMemoryError異常。
java