一. JVM運(yùn)行時數(shù)據(jù)區(qū)
java 虛擬機(jī)在執(zhí)行java程序的時候,會將內(nèi)存劃分為若干個不同的區(qū)域,都各自有自己的用途,下圖是java 虛擬機(jī)運(yùn)行時數(shù)據(jù)區(qū)圖:
1 方法區(qū)
該區(qū)主要用來存儲已被虛擬機(jī)加載的類信息,常量,靜態(tài)變量,以及JIT編譯完之后的代碼等,很多人將方法區(qū)稱為"永久代",其實(shí)兩者是不等價的,僅僅是將GC分代收集擴(kuò)展到方法區(qū),這樣hotSpot 的垃圾回收器就可以像管理java堆一樣管理這部分內(nèi)存,對于JRocket,J9,是沒有這個概念的。
2 虛擬機(jī)棧
線程私有的,生命周期和線程一樣,描述了java 方法執(zhí)行的內(nèi)存模型,用棧幀來存儲局部變量表,操作數(shù)棧,動態(tài)鏈接,方法出口,方法執(zhí)行對應(yīng)了進(jìn)棧和出棧,這邊規(guī)定了StackOverflowError : 線程所請求的棧深度大于虛擬機(jī)所允許的深度,以及由于支持動態(tài)拓展之后出現(xiàn)的無法申請到足夠的內(nèi)存而拋出的OutOfMemoryError.
3 本地方法棧
虛擬機(jī)使用的Native方法服務(wù),與虛擬機(jī)棧類似,也會拋StackoverflowError以及OutOfMemoryError.
4 java堆
虛擬機(jī)管理的內(nèi)存中最大的一塊,是所有線程共享的一塊區(qū)域,"幾乎"所有的對象實(shí)例都是在這里分配內(nèi)存,隨著JIT的發(fā)展與逃逸分析技術(shù)成熟,棧上分配,標(biāo)量替換等使得對象的分配都在堆上面變得不是那么絕對。這一塊也是GC回收器管理的主要區(qū)域,java堆空間可劃分為:新生代和老年代,再細(xì)分就是,新生代里面可以又劃分為:Eden區(qū),F(xiàn)rom Survivior,To Survivor. 這邊還有一個是TLAB(Thread Local Allocation Buffer), 在堆中創(chuàng)建出來的多個線程私有的分配緩沖區(qū)。
5 程序計(jì)數(shù)器
當(dāng)前線程執(zhí)行的字節(jié)碼的行號指示器,各個線程之間都獨(dú)立存儲私有這一塊內(nèi)存區(qū)域,注意當(dāng)執(zhí)行的Native方法時,該計(jì)數(shù)器為空,也是唯一一個在java 虛擬機(jī)規(guī)范中沒有規(guī)定任何的OutOfMemoryError的區(qū)域。
二. 非JVM運(yùn)行時數(shù)據(jù)區(qū)
1 直接內(nèi)存
并不是虛擬機(jī)運(yùn)行時數(shù)據(jù)區(qū)的一部分,也不是java虛擬機(jī)規(guī)范中定義的內(nèi)存區(qū)域,java 通過在堆中的DirectByteBuffer 對象作為這塊內(nèi)存的引用進(jìn)行操作。