java虛擬機(jī)會(huì)在執(zhí)行程序的過程中把管理的內(nèi)存劃分成幾個(gè)數(shù)據(jù)區(qū):程序計(jì)數(shù)器、java 虛擬機(jī)棧、本地方法棧、java堆、方法區(qū)。?
1、程序計(jì)算器:
這個(gè)比較好理解,就是線程執(zhí)行字節(jié)碼的行標(biāo),就是用來記錄程序執(zhí)行到哪里了,這樣程序才知道接下來應(yīng)該運(yùn)行哪里。因?yàn)槭菫槊總€(gè)線程記錄了,所以比較理所當(dāng)然的就是線程私有啦。
這個(gè)計(jì)算器的值也很好理解,如果是執(zhí)行的是Java代碼,記錄的就是字節(jié)碼指令地址;如果執(zhí)行是native方法(大概就是一個(gè)java調(diào)用的非java的接口),那計(jì)數(shù)器就是空值。
這個(gè)計(jì)算器還有一個(gè)特點(diǎn)就是唯一一個(gè)java虛擬機(jī)規(guī)范沒有規(guī)定任何OutOfMemoryError情況的區(qū)域。
2、java 虛擬機(jī)棧:
虛擬機(jī)棧其實(shí)就是java方法執(zhí)行的內(nèi)存模塊,方法的運(yùn)行的這個(gè)過程就是對(duì)應(yīng)一個(gè)棧幀(方法在執(zhí)行的同時(shí)會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息)從虛擬機(jī)棧進(jìn)棧出棧的過程。這部分也是線程私有的。
java虛擬機(jī)規(guī)范對(duì)虛擬機(jī)棧規(guī)定了兩種的異常情況:
1)線程請(qǐng)求棧的深度大于java虛擬機(jī)規(guī)范規(guī)定的深度,這時(shí)會(huì)拋出StackOverFlowError異常。
2)當(dāng)虛擬機(jī)棧動(dòng)態(tài)拓展時(shí)(大部分虛擬機(jī)是允許的),拓展時(shí)無法申請(qǐng)到足夠的內(nèi)存,這時(shí)會(huì)拋出OutOfMemoryError異常。
3、本地方法棧 :
與虛擬機(jī)棧很類似,主要的區(qū)別在于本地方法棧是為虛擬機(jī)使用到Native方法服務(wù)的。但是java虛擬機(jī)規(guī)范并沒有強(qiáng)制對(duì)本地方法棧進(jìn)行規(guī)定,所以有一些虛擬機(jī)甚至?xí)烟摂M機(jī)棧和本地方法棧合二為一。
4、java堆:
一般情況下,java堆是java虛擬機(jī)管理中的最大一塊。java堆在java虛擬機(jī)啟時(shí)創(chuàng)建,是被所有線程共享的,是大多數(shù)的實(shí)例都要在這里分配內(nèi)存的(棧上分配和標(biāo)量替換導(dǎo)致一些實(shí)例不在堆上分配)。是垃圾收集器管理的主要區(qū)域。
java虛擬機(jī)規(guī)范規(guī)定,java堆只需要內(nèi)存是邏輯連續(xù)的就可以,不一定是要物理連續(xù)(主流虛擬機(jī)通過-Xmx和-Xms來控制java堆的拓展)。拓展時(shí)無法申請(qǐng)到足夠的內(nèi)存,這時(shí)會(huì)拋出OutOfMemoryError異常。
5、方法區(qū):
這部分的作用主要用于存儲(chǔ)已經(jīng)被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼。這部分是被所有線程共享的。
java虛擬機(jī)規(guī)范規(guī)定,方法區(qū)也是只需要內(nèi)存是邏輯連續(xù)的就可以,不一定是要物理連續(xù),可以動(dòng)態(tài)拓展,并且可以選擇不實(shí)現(xiàn)垃圾收集。雖然這部分實(shí)現(xiàn)垃圾收集效果并不好,但是也是有必要的。如果沒有垃圾收集,可能會(huì)出現(xiàn)內(nèi)存泄漏的情況。拓展時(shí)無法申請(qǐng)到足夠的內(nèi)存,這時(shí)會(huì)拋出OutOfMemoryError異常。
方法區(qū)有一個(gè)部分叫運(yùn)行時(shí)常量池。java虛擬機(jī)規(guī)范規(guī)定并沒有對(duì)運(yùn)行時(shí)常量池作任何細(xì)節(jié)的要求。運(yùn)行時(shí)常量池具有動(dòng)態(tài)性,預(yù)置在Class文件中常量池的內(nèi)容能進(jìn)入運(yùn)行時(shí)常量池,運(yùn)行期間的新的常量也是可能將加入。