java虛擬機內存模型?
1.什么是jvm?(1)jvm是一種用于計算設備的規范,它是一個虛構出來的機器,是通過在實際的計算機上仿真模擬各種功能實現的。(2)jvm包含一套字節碼指令集,一組寄存器,一個棧,一個垃圾回收堆和一個存儲方法域。(3)JVM屏蔽了與具體操作系統平臺相關的信息,使Java程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平臺上不加修改地運行。JVM在執行字節碼時,實際上最終還是把字節碼解釋成具體平臺上的機器指令執行。
2.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就是為了支持與操作系統無關,實現跨平臺。
3.JVM原理(1)jvm是java的核心和基礎,在java編譯器和os平臺之間的虛擬處理器,可在上面執行字節碼程序。(2)java編譯器只要面向jvm,生成jvm能理解的字節碼文件。java源文件經編譯成字節碼程序,通過jvm將每條指令翻譯成不同的機器碼,通過特定平臺運行。
4. 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類。5. 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執行引擎實例則對應了屬于用戶運行程序的線程它是線程級別的
6、JVM內存模型
(1)java代碼具體執行過程如下圖,
(2)運行時數據區,即jvm內存結構圖如下圖
(3)運行時數據區存儲了哪些數據?
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方法。
7、JVM內存溢出的情況
a) 程序計數器(Program Counter Register)
每條線程都有一個獨立的的程序計數器,各線程間的計數器互不影響,因此該區域是線程私有的。該內存區域是唯一一個在Java虛擬機規范中沒有規定任何OOM(內存溢出:OutOfMemoryError)情況的區域。
b)Java虛擬機棧(Java Virtual Machine Stacks)
在Java虛擬機規范中,對這個區域規定了兩種異常情況:
1、如果線程請求的棧深度大于虛擬機所允許的深度,將拋出StackOverflowError異常。
2、如果虛擬機在動態擴展棧時無法申請到足夠的內存空間,則拋出OutOfMemoryError異常。
這兩種情況存在著一些互相重疊的地方:當棧空間無法繼續分配時,到底是內存太小,還是已使用的棧空間太大,其本質上只是對同一件事情的兩種描述而已。
在單線程的操作中,無論是由于棧幀太大,還是虛擬機棧空間太小,當棧空間無法分配時,虛擬機拋出的都是StackOverflowError異常,而不會得到OutOfMemoryError異常。
而在多線程環境下,則會拋出OutOfMemoryError異常。
c)堆Java Heap
Java Heap是Java虛擬機所管理的內存中最大的一塊,它是所有線程共享的一塊內存區域。幾乎所有的對象實例和數組都在這類分配內存。Java Heap是垃圾收集器管理的主要區域,因此很多時候也被稱為“GC堆”。
根據Java虛擬機規范的規定,Java堆可以處在物理上不連續的內存空間中,只要邏輯上是連續的即可。如果在堆中沒有內存可分配時,并且堆也無法擴展時,將會拋出OutOfMemoryError異常。
d)方法區域,又被稱為“永久代”,當方法區無法滿足內存分配需求時,將拋出OutOfMemoryError異常。