笔记:Java虚拟机运行时数据区
Java虛擬機(jī)在執(zhí)行Java程序的過(guò)程中會(huì)把它管的內(nèi)存劃分為以下若干個(gè)不同的區(qū)域:
?
1、程序計(jì)數(shù)器
程序計(jì)數(shù)器是一塊較小的內(nèi)存空間,它可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器;由于Java虛擬機(jī)的多線程是通過(guò)線程輪流切換并分配處理器執(zhí)行時(shí)間的方式來(lái)實(shí)現(xiàn),在任何一個(gè)確定的時(shí)刻,一個(gè)處理器(對(duì)于多核處理器來(lái)說(shuō)是一個(gè)內(nèi)核)都只能執(zhí)行一個(gè)線程中的指令,因此為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要一個(gè)獨(dú)立的程序計(jì)數(shù)器來(lái)記錄線程之前執(zhí)行到哪里了。
如果線程正在執(zhí)行的是一個(gè)Java方法,這個(gè)計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令地址;如果正在執(zhí)行的是一個(gè)Native方法,這個(gè)計(jì)數(shù)器值則為空(Undefined)。
這個(gè)內(nèi)存區(qū)域是唯一一個(gè)在Java虛擬機(jī)規(guī)范中沒(méi)有規(guī)定任何OutOfMemoryError情況的區(qū)域。
是線程私有的內(nèi)存空間。
?
2、Java虛擬機(jī)棧
是線程私有內(nèi)存空間。
虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法在執(zhí)行的時(shí)候都會(huì)創(chuàng)建一個(gè)棧幀,用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈表、方法的出口信息等。每一個(gè)方法從調(diào)用直到執(zhí)行完成的過(guò)程,就對(duì)應(yīng)這一個(gè)棧幀在虛擬機(jī)棧中的入棧和出棧。
局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類(lèi)型(boolean、byte、char、short、int、float、long、double)、對(duì)象引用(reference類(lèi)型)和returnAddress類(lèi)型(指向了一條字節(jié)碼指令的地址)。其中64位的long和double類(lèi)型占用兩個(gè)局部變量空間,其余數(shù)據(jù)類(lèi)型占用1個(gè)變量空間。
局部變量表所需的內(nèi)存空間在編譯期間完成分配,當(dāng)進(jìn)入一個(gè)方法時(shí),這個(gè)方法需要在幀中分配多大的局部變量空間是完全確定的,在方法運(yùn)行期間是不會(huì)改變局部變量表大小的。
在Java虛擬機(jī)規(guī)范中,這個(gè)區(qū)域規(guī)定了兩種異常情況:一、如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常;二、如果虛擬機(jī)可動(dòng)態(tài)擴(kuò)展(當(dāng)前大部分虛擬機(jī)都可以動(dòng)態(tài)擴(kuò)展),如果擴(kuò)展時(shí)無(wú)法申請(qǐng)到足夠的內(nèi)存,就會(huì)拋出OutOfMemoryError異常。
?
3、本地方法棧
本地方法棧和Java虛擬機(jī)棧發(fā)揮的作用非常相似,Java虛擬機(jī)棧是為虛擬機(jī)執(zhí)行Java方法服務(wù)的,而本地方法棧是為虛擬機(jī)使用Native方法服務(wù)的。在虛擬機(jī)規(guī)范中對(duì)本地方法棧使用的語(yǔ)言、使用方式和數(shù)據(jù)結(jié)構(gòu)沒(méi)有強(qiáng)制規(guī)定,因此具體的虛擬機(jī)可以自由實(shí)現(xiàn)。
在HotSpot虛擬機(jī)中把虛擬機(jī)棧和本地方法棧合二為一。
是線程私有內(nèi)存空間。
?
4、Java堆
? Java堆是被所有線程共享的一塊內(nèi)存區(qū)域,是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊。在虛擬機(jī)啟動(dòng)的時(shí)候創(chuàng)建。
Java程序創(chuàng)建的對(duì)象實(shí)例幾乎都在這里分配內(nèi)存;在Java虛擬機(jī)規(guī)范中描述:所有的對(duì)象實(shí)例以及數(shù)據(jù)都要在堆上分配,但是隨著JIT編譯器的發(fā)展和逃逸分析技術(shù)逐漸成熟,棧上分配、標(biāo)量替換優(yōu)化技術(shù)將會(huì)導(dǎo)致一些微妙的變化發(fā)生,所有對(duì)象分配都在堆上也漸漸變得不是那么“絕對(duì)”了。
Java堆是垃圾收集器管理的主要區(qū)域。
Java堆空間還可以分為:新生代和老年代,新生代又可以細(xì)分為:Eden空間、From Survivor空間和To Survivor空間。
如果在堆上沒(méi)有內(nèi)存空間可以完成對(duì)象實(shí)例分配,并且堆也無(wú)法再擴(kuò)展時(shí),將會(huì)拋出OutOfMemoryOut異常。
?
5、方法區(qū)
方法區(qū)也是各個(gè)線程共享的內(nèi)存區(qū)域。
方法區(qū)用于存儲(chǔ)已被虛擬機(jī)加載的類(lèi)信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。
在HotSpot虛擬機(jī)上,GC分代收集擴(kuò)展到了方法區(qū),或者說(shuō)使用永久代來(lái)實(shí)現(xiàn)方法區(qū),這樣可以像管理Java堆內(nèi)存一樣管理方法區(qū)內(nèi)存,一般GC和老年代GC一起觸發(fā),所以在HotSpot虛擬機(jī)中,方法區(qū)也被稱(chēng)為“永久代”。
方法區(qū)的內(nèi)存回收主要是針對(duì)常量池的回收和對(duì)類(lèi)型的卸載(不過(guò)條件相當(dāng)苛刻)。
方法區(qū)無(wú)法滿足內(nèi)存分配需求時(shí),將拋出OutOfMemoryError異常。
?
6、運(yùn)行時(shí)常量池
運(yùn)行時(shí)常量池是方法區(qū)的一部分。
Class文件中除了有類(lèi)的版本、字段、方法、接口等描述信息外,還有一項(xiàng)信息常量池,用于存放編譯器生成的的各種字面常量和符號(hào)引用,這部分內(nèi)容將在類(lèi)加載后進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池中存放。
運(yùn)行時(shí)常量池相對(duì)于Class文件常量池的另外一個(gè)重要特性是具備動(dòng)態(tài)性,Java語(yǔ)言并不要求常量一定只有編譯器才產(chǎn)生,運(yùn)行期間也可能將新的常量放入到常量池中。
當(dāng)常量池?zé)o法申請(qǐng)到內(nèi)存時(shí)將會(huì)拋出OutOfMemoryError異常。
?
7、直接內(nèi)存
直接內(nèi)存并不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,也不是Java虛擬機(jī)規(guī)范中定義的內(nèi)存區(qū)域。但是這部分內(nèi)存也會(huì)被平凡的用到,也會(huì)出現(xiàn)OutOfMemoryError異常。
JDK1.4引入了NIO類(lèi),一種基于通道(channel)與緩沖區(qū)(Buffer)的I/O方式,它可以使用Native函數(shù)庫(kù)直接分配堆外內(nèi)存,然后通過(guò)一個(gè)存儲(chǔ)在Java堆中的DirectButeBuffer對(duì)象作為這塊內(nèi)存的引用進(jìn)行操作。這種方式避免了Java堆和Native堆中來(lái)回復(fù)制數(shù)據(jù),在一些場(chǎng)景中可以顯著提高性能。
?
轉(zhuǎn)載于:https://www.cnblogs.com/super-jing/p/10786147.html
總結(jié)
以上是生活随笔為你收集整理的笔记:Java虚拟机运行时数据区的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【转】漫画:Bitmap算法
- 下一篇: RE validation in Jav