jvm内存模型及分配
1.什么是jvm?
(1)jvm是一種用于計(jì)算設(shè)備的規(guī)范,它是一個(gè)虛構(gòu)出來(lái)的機(jī)器,是通過(guò)在實(shí)際的計(jì)算機(jī)上仿真模擬各種功能實(shí)現(xiàn)的。
(2)jvm包含一套字節(jié)碼指令集,一組寄存器,一個(gè)棧,一個(gè)垃圾回收堆和一個(gè)存儲(chǔ)方法域。
(3)JVM屏蔽了與具體操作系統(tǒng)平臺(tái)相關(guān)的信息,使Java程序只需生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼),就可以在多種平臺(tái)上不加修改地運(yùn)行。
JVM在執(zhí)行字節(jié)碼時(shí),實(shí)際上最終還是把字節(jié)碼解釋成具體平臺(tái)上的機(jī)器指令執(zhí)行。
2.jdk、jre、jvm是什么關(guān)系?
(1)JRE(Java Runtime Environment),也就是java平臺(tái)。所有的java程序都要在JRE環(huán)境下才能運(yùn)行。
(2)JDK(Java Development Kit),是開(kāi)發(fā)者用來(lái)編譯、調(diào)試程序用的開(kāi)發(fā)包。JDK也是JAVA程序需要在JRE上運(yùn)行。
(3)JVM(Java Virtual Machine),是JRE的一部分。它是一個(gè)虛構(gòu)出來(lái)的計(jì)算機(jī),是通過(guò)在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來(lái)實(shí)現(xiàn)的。
JVM有自己完善的硬件架構(gòu),如處理器、堆棧、寄存器等,還具有相應(yīng)的指令系統(tǒng)。
Java語(yǔ)言最重要的特點(diǎn)就是跨平臺(tái)運(yùn)行。使用JVM就是為了支持與操作系統(tǒng)無(wú)關(guān),實(shí)現(xiàn)跨平臺(tái)。
3.JVM原理
(1)jvm是java的核心和基礎(chǔ),在java編譯器和os平臺(tái)之間的虛擬處理器,可在上面執(zhí)行字節(jié)碼程序。
(2)java編譯器只要面向jvm,生成jvm能理解的字節(jié)碼文件。java源文件經(jīng)編譯成字節(jié)碼程序,通過(guò)jvm將每條指令翻譯成不同的機(jī)器碼
,通過(guò)特定平臺(tái)運(yùn)行。
4. JVM執(zhí)行程序的過(guò)程
1) 加載.class文件?
2) 管理并分配內(nèi)存?
3) 執(zhí)行垃圾收集
JRE(java運(yùn)行時(shí)環(huán)境)由JVM構(gòu)造的java程序的運(yùn)行環(huán),也是Java程序運(yùn)行的環(huán)境,但是他同時(shí)一個(gè)操作系統(tǒng)的一個(gè)應(yīng)用程序一個(gè)進(jìn)程,
因此他也有他自己的運(yùn)行的生命周期,也有自己的代碼和數(shù)據(jù)空間。
JVM在整個(gè)jdk中處于最底層,負(fù)責(zé)于操作系統(tǒng)的交互,用來(lái)屏蔽操作系統(tǒng)環(huán)境,
提供一個(gè)完整的Java運(yùn)行環(huán)境,因此也就虛擬計(jì)算機(jī)。
操作系統(tǒng)裝入JVM是通過(guò)jdk中Java.exe來(lái)完成,
通過(guò)下面4步來(lái)完成JVM環(huán)境:
1) 創(chuàng)建JVM裝載環(huán)境和配置?
2) 裝載JVM.dll?
3) 初始化JVM.dll并掛界到JNIENV(JNI調(diào)用接口)實(shí)例
4) 調(diào)用JNIEnv實(shí)例裝載并處理class類(lèi)。
5. JVM的生命周期
1) JVM實(shí)例對(duì)應(yīng)了一個(gè)獨(dú)立運(yùn)行的java程序它是進(jìn)程級(jí)別?
a) 啟動(dòng)。啟動(dòng)一個(gè)Java程序時(shí),一個(gè)JVM實(shí)例就產(chǎn)生了,任何一個(gè)擁有public static void?
main(String[] args)函數(shù)的class都可以作為JVM實(shí)例運(yùn)行的起點(diǎn)?
b) 運(yùn)行。main()作為該程序初始線程的起點(diǎn),任何其他線程均由該線程啟動(dòng)。JVM內(nèi)部有兩種線程:守護(hù)線程和非守護(hù)線程,main()屬于非守護(hù)線程,守護(hù)線程通常由JVM自己使用,java程序也可以表明自己創(chuàng)建的線程是守護(hù)線程?
c) 消亡。當(dāng)程序中的所有非守護(hù)線程都終止時(shí),JVM才退出;若安全管理器允許,程序也可以使用Runtime類(lèi)或者System.exit()來(lái)退出?
2) JVM執(zhí)行引擎實(shí)例則對(duì)應(yīng)了屬于用戶運(yùn)行程序的線程它是線程級(jí)別的
?6、JVM內(nèi)存模型
(1)java代碼具體執(zhí)行過(guò)程如下圖,
(2)運(yùn)行時(shí)數(shù)據(jù)區(qū),即jvm內(nèi)存結(jié)構(gòu)圖如下圖
(3)運(yùn)行時(shí)數(shù)據(jù)區(qū)存儲(chǔ)了哪些數(shù)據(jù)?
a) 程序計(jì)數(shù)器(PC寄存器)
??由于在JVM中,多線程是通過(guò)線程輪流切換來(lái)獲得CPU執(zhí)行時(shí)間的,因此,在任一具體時(shí)刻,一個(gè)CPU的內(nèi)核只會(huì)執(zhí)行一條線程中的指令,
因此,為了能夠使得每個(gè)線程都在線程切換后能夠恢復(fù)在切 換 之前的程序執(zhí)行位置,每個(gè)線程都需要有自己獨(dú)立的程序計(jì)數(shù)器,并且不能互相被干擾,
否則就會(huì)影響到程序的正常執(zhí)行次序。因此,可以這么說(shuō),程序計(jì)數(shù)器是每個(gè)線程所私有的。由于程序計(jì)數(shù)器中存儲(chǔ)的數(shù)據(jù)所占空間的大小不會(huì)隨程序的執(zhí)行而發(fā)生改變,
因此,對(duì)于程序計(jì)數(shù)器是不會(huì)發(fā)生內(nèi)存溢出現(xiàn)象(OutOfMemory)的。
b) java棧
? Java棧中存放的是一個(gè)個(gè)的棧幀,每個(gè)棧幀對(duì)應(yīng)一個(gè)被調(diào)用的方法,在棧幀中包括局部變量表(Local Variables)、操作數(shù)棧(Operand Stack)、
指向當(dāng)前方法所屬的類(lèi)的運(yùn)行時(shí)常量池(運(yùn)行時(shí)常量池的概念在方法區(qū)部分會(huì)談到)的引用(Reference to runtime constant pool)、
方法返回地址(Return Address)和一些額外的附加信息。當(dāng)線程執(zhí)行一個(gè)方法時(shí),就會(huì)隨之創(chuàng)建一個(gè)對(duì)應(yīng)的棧幀,并將建立的棧幀壓棧。當(dāng)方法執(zhí)行完畢之后,便會(huì)將棧幀出棧。
c)本地方法棧
本地方法棧與Java棧的作用和原理非常相似。區(qū)別只不過(guò)是Java棧是為執(zhí)行Java方法服務(wù)的,而本地方法棧則是為執(zhí)行本地方法(Native Method)服務(wù)的
d)堆
Java中的堆是用來(lái)存儲(chǔ)對(duì)象本身的以及數(shù)組(數(shù)組引用是存放在Java棧中的)。堆是被所有線程共享的,在JVM中只有一個(gè)堆。
e)方法區(qū)
與堆一樣,是被線程共享的區(qū)域。在方法區(qū)中,存儲(chǔ)了每個(gè)類(lèi)的信息(包括類(lèi)的名稱(chēng)、方法信息、字段信息)、靜態(tài)變量、常量以及編譯器編譯后的代碼等。
在Class文件中除了類(lèi)的字段、方法、接口等描述信息外,還有一項(xiàng)信息是常量池,用來(lái)存儲(chǔ)編譯期間生成的字面量和符號(hào)引用。
在方法區(qū)中有一個(gè)非常重要的部分就是運(yùn)行時(shí)常量池,它是每一個(gè)類(lèi)或接口的常量池的運(yùn)行時(shí)表示形式,在類(lèi)和接口被加載到JVM后,
對(duì)應(yīng)的運(yùn)行時(shí)常量池就被創(chuàng)建出來(lái)。當(dāng)然并非Class文件常量池中的內(nèi)容才能進(jìn)入運(yùn)行時(shí)常量池,在運(yùn)行期間也可將新的常量放入運(yùn)行時(shí)常量池中,比如String的intern方法。
7、JVM內(nèi)存溢出的情況
a)?程序計(jì)數(shù)器(Program Counter Register)
每條線程都有一個(gè)獨(dú)立的的程序計(jì)數(shù)器,各線程間的計(jì)數(shù)器互不影響,因此該區(qū)域是線程私有的。該內(nèi)存區(qū)域是唯一一個(gè)在Java虛擬機(jī)規(guī)范中沒(méi)有規(guī)定任何OOM(內(nèi)存溢出:OutOfMemoryError)情況的區(qū)域。
b)Java虛擬機(jī)棧(Java Virtual Machine Stacks)
在Java虛擬機(jī)規(guī)范中,對(duì)這個(gè)區(qū)域規(guī)定了兩種異常情況:
??? ?1、如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常。
???? 2、如果虛擬機(jī)在動(dòng)態(tài)擴(kuò)展棧時(shí)無(wú)法申請(qǐng)到足夠的內(nèi)存空間,則拋出OutOfMemoryError異常。
???? ? ? 這兩種情況存在著一些互相重疊的地方:當(dāng)棧空間無(wú)法繼續(xù)分配時(shí),到底是內(nèi)存太小,還是已使用的棧空間太大,其本質(zhì)上只是對(duì)同一件事情的兩種描述而已。
? 在單線程的操作中,無(wú)論是由于棧幀太大,還是虛擬機(jī)棧空間太小,當(dāng)棧空間無(wú)法分配時(shí),虛擬機(jī)拋出的都是StackOverflowError異常,而不會(huì)得到OutOfMemoryError異常。
? ? ? ? 而在多線程環(huán)境下,則會(huì)拋出OutOfMemoryError異常。
c)堆Java?Heap
Java?Heap是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊,它是所有線程共享的一塊內(nèi)存區(qū)域。幾乎所有的對(duì)象實(shí)例和數(shù)組都在這類(lèi)分配內(nèi)存。Java?Heap是垃圾收集器管理的主要區(qū)域,因此很多時(shí)候也被稱(chēng)為“GC堆”。
???? 根據(jù)Java虛擬機(jī)規(guī)范的規(guī)定,Java堆可以處在物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可。如果在堆中沒(méi)有內(nèi)存可分配時(shí),并且堆也無(wú)法擴(kuò)展時(shí),將會(huì)拋出OutOfMemoryError異常。 ??
d)方法區(qū)域,又被稱(chēng)為“永久代”,當(dāng)方法區(qū)無(wú)法滿足內(nèi)存分配需求時(shí),將拋出OutOfMemoryError異常。
參考資料:http://www.cnblogs.com/dolphin0520/p/3613043.html
參考資料:http://www.cnblogs.com/sunada2005/p/3577799.html
參考資料:http://blog.csdn.net/ns_code/article/details/17565503
總結(jié)
以上是生活随笔為你收集整理的jvm内存模型及分配的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 通过Flask和Redis构造一个动态维
- 下一篇: Docker 1.10版本发布