一.本地方法棧
每個線程獨(dú)享一塊本地方法椃睦埃空間利职,存儲該線程運(yùn)行過程中調(diào)用的本地方法(被native關(guān)鍵字修飾的方法)執(zhí)行過程中的局部變量滔灶。
二.程序計(jì)數(shù)器
每個線程獨(dú)享一塊程序計(jì)數(shù)器空間送膳,存儲該線程運(yùn)行到的那行代碼在方法區(qū)中的內(nèi)存地址员魏,可以簡單理解為那行代碼的行號。程序計(jì)數(shù)器的值由字節(jié)碼執(zhí)行引擎負(fù)責(zé)修改叠聋。
為什么要設(shè)計(jì)程序計(jì)數(shù)器撕阎?因?yàn)镴VM是多線程運(yùn)行的,發(fā)生線程切換時需要將被掛起的線程運(yùn)行狀態(tài)記錄下來碌补,以便該線程再次運(yùn)行時能從上次的位置繼續(xù)執(zhí)行虏束。
三.方法區(qū)(元空間)
方法區(qū)JDK8之前叫永久代棉饶,JDK8之后叫元空間(Metaspace)。存儲常量镇匀、靜態(tài)變量在堆中的內(nèi)存地址照藻、類信息。
四.棧
每個線程獨(dú)享一塊椏勇桑空間岩梳,該線程執(zhí)行的每個方法在棧內(nèi)部又獨(dú)享一塊空間,稱為棧幀晃择。
public static void main(String[] args) {
System.out.println("1 + 2 = " + add());
System.out.println("Hello world!");
}
public static int add() {
int a = 1;
int b = 2;
return a + b;
}
上面這段示例代碼的棧內(nèi)部結(jié)構(gòu)如圖:
每個棧幀內(nèi)部由以下4部分組成:
1.局部變量表
方法內(nèi)部的局部變量在堆或方法區(qū)中的內(nèi)存地址冀值。
2.操作數(shù)棧
棧內(nèi)部用于計(jì)算的臨時數(shù)據(jù)存儲區(qū)。
3.動態(tài)鏈接
存儲當(dāng)前棧幀所屬方法在方法區(qū)中的內(nèi)存地址宫屠。
4.方法出口
存儲當(dāng)前棧幀所屬方法的運(yùn)行出口列疗,即當(dāng)前方法運(yùn)行結(jié)束后繼續(xù)執(zhí)行哪個方法哪一行代碼,在方法區(qū)中的內(nèi)存地址浪蹂,可以簡單理解為那行代碼的行號抵栈。
五.堆
堆內(nèi)存分為年輕代(YoungGen)和老年代(OldGen),默認(rèn)情況下坤次,年輕代占堆內(nèi)存的1/3古劲,老年代占2/3。年輕代中又分為生成區(qū)(Eden)和幸存區(qū)(Survivor)缰猴,生成區(qū)占年輕代4/5产艾,幸存區(qū)占年輕代1/5。幸存區(qū)中分為兩個相等大小的區(qū)域S0和S1滑绒,也叫From區(qū)和To區(qū)闷堡。每次執(zhí)行GC后,F(xiàn)rom區(qū)和To區(qū)會進(jìn)行交換疑故。綜上杠览,默認(rèn)情況下,各區(qū)域內(nèi)存大小比例為OldGen:Eden:S0:S1 = 20:8:1:1纵势。