程序計(jì)數(shù)器:是線(xiàn)程私有的,是一塊較小的內(nèi)存空間,當(dāng)前線(xiàn)程所執(zhí)行的字節(jié)碼的行號(hào)指示器。JAVA虛擬機(jī)的多線(xiàn)程是通過(guò)線(xiàn)程輪流切換并分配處理器執(zhí)行時(shí)間的方式來(lái)實(shí)現(xiàn)。在任何一個(gè)確定的時(shí)刻,一個(gè)處理器都只會(huì)執(zhí)行一條線(xiàn)程中的指令。因此,為了線(xiàn)程切換后能恢復(fù)到正確的執(zhí)行位置,每條線(xiàn)程都需要一個(gè)獨(dú)立的程序計(jì)數(shù)器,各個(gè)線(xiàn)程之間計(jì)數(shù)器互不影響,獨(dú)立存儲(chǔ)。沒(méi)有規(guī)范OutOfMemoryError情況的區(qū)域。
虛擬機(jī)棧:也是線(xiàn)程私有的。描述的是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è)棧幀一個(gè)棧幀出棧到入棧的過(guò)程。異常規(guī)范:如果線(xiàn)程請(qǐng)求的棧深度大于虛擬機(jī)棧所允許的深度,將拋出Stack OverflowError異常;如果虛擬機(jī)棧可以動(dòng)態(tài)擴(kuò)展,如果擴(kuò)展無(wú)法申請(qǐng)到足夠的內(nèi)存,就會(huì)拋出OutOfMemoryError異常。下圖展示了虛擬機(jī)棧壓棧的示例。

本地方法棧:線(xiàn)程私有,本地方法棧與虛擬機(jī)棧所發(fā)揮的作用是非常相似的,區(qū)別是虛擬機(jī)棧為虛擬機(jī)執(zhí)行JAVA方法服務(wù),而本地方法棧則為虛擬機(jī)使用的native方法服務(wù)。也會(huì)拋出StackOverFlowError和OutOfMemoryError異常。
JAVA堆:JAVA堆是被所有線(xiàn)程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建時(shí)。此內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例。但是隨著JIT編譯器的發(fā)展與逃逸分析技術(shù)逐漸成熟,棧上分配、標(biāo)量替換優(yōu)化技術(shù)的變化,在堆上分配變得不那么絕對(duì)了。JAVA堆是垃圾收集器管理的主要區(qū)域。從內(nèi)存回收的角度來(lái)看,由于現(xiàn)在收集器基本都采用分代收集算法,所以JAVA堆可以細(xì)分為:新生代和老年代,在細(xì)致一點(diǎn)可以分為Eden區(qū)、From Survivor空間、To Survivor空間。從內(nèi)存分配角度看,線(xiàn)程共享的JAVA堆中可能劃分出多個(gè)線(xiàn)程私有的分配緩沖區(qū)(Thread Local Allocation Buffer,TLAB)。
方法區(qū):與JAVA堆一樣是各個(gè)線(xiàn)程共享的內(nèi)存區(qū)域,它用于存儲(chǔ)已被虛擬機(jī)加載的類(lèi)信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。該區(qū)域在HotSpot虛擬機(jī)中也可稱(chēng)為永久代,該稱(chēng)為只是為了將該區(qū)域納入到GC收集中去,在其他虛擬機(jī)中并沒(méi)有這樣定義。
什么是運(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)行期間也可能將新的常量放入到池中,利用的比較多的是String類(lèi)的intern()方法。
什么是直接內(nèi)存?
直接內(nèi)存并不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,也不是JAVA虛擬機(jī)規(guī)范中定義的內(nèi)存區(qū)域,在JDK1.4中新加入了NIO類(lèi),引入了一種基于通道(Channel)和緩沖區(qū)(Buffer)的I/O方式,他可以使用Native函數(shù)庫(kù)直接分配堆外內(nèi)存,然后通過(guò)一個(gè)存儲(chǔ)在JAVA堆中的DirectByteBuffer對(duì)象作為這塊內(nèi)存的引用進(jìn)行操作。