-
Java虛擬機(jī)內(nèi)存
???Java虛擬機(jī)在執(zhí)行Java程序的時(shí)候會(huì)將它管理的內(nèi)存分為若干個(gè)不同的數(shù)據(jù)區(qū)域。不同的區(qū)域用途也各不相同,具體內(nèi)存模型圖如下圖所示:
Java內(nèi)存模型.png
??其中橙色部分為線程私有的數(shù)據(jù)區(qū)域,藍(lán)色部分為線程共享的數(shù)據(jù)區(qū)域
程序計(jì)數(shù)器
??程序計(jì)數(shù)器是一塊較小的內(nèi)存空間,主要記錄當(dāng)前線程執(zhí)行的虛擬機(jī)字節(jié)碼地址,如果執(zhí)行的是Native方法,則程序計(jì)數(shù)器值為空。
虛擬機(jī)棧
??虛擬機(jī)棧描述的是Java方法的內(nèi)存模型:每個(gè)方法在執(zhí)行的時(shí)候都會(huì)創(chuàng)建一個(gè)棧幀,用來存儲(chǔ)局部標(biāo)量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息
本地方法棧
??本地方法棧與虛擬機(jī)棧作用相似,不同的是本地方法棧是用于描述Native方法的內(nèi)存模型
堆
??Java堆是Java虛擬機(jī)所管理內(nèi)存中最大的一塊,也是被所有線程共享的一塊內(nèi)存區(qū)域,該區(qū)域主要是存放對(duì)象實(shí)例。Java堆也是垃圾收集器的主要區(qū)域,從內(nèi)存回收的角度來看,由于現(xiàn)在收集器基本都采用分代收集算法,所以Java堆還可以細(xì)分為新生代和老年代,再細(xì)致一點(diǎn)的有Eden空間、From Survivor空間、To Survivor空間等
方法區(qū)
??方法區(qū)也是被各個(gè)線程共享的內(nèi)存區(qū)域,主要用于存儲(chǔ)被虛擬機(jī)加載的類信息、常量靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù) - Java虛擬機(jī)是如何操作這些區(qū)域的
結(jié)合代碼重點(diǎn)了解一下JVM運(yùn)行時(shí)數(shù)據(jù)區(qū),主要是虛擬機(jī)棧的分析
com.kons;
public class Test{
public static void main(String[] args){
int a=1;
int b=2;
int c=add(a,b);
}
public static int add(int a,int b){
return a+b;
}
}
首先Test類被編譯成class文件,通過類加載子系統(tǒng)加載到內(nèi)存中。然后,JVM會(huì)給執(zhí)行的線程分配程序計(jì)數(shù)器、虛擬機(jī)棧、以及本地方法棧,如圖所示:

當(dāng)執(zhí)行main方法的時(shí)候,會(huì)給main方法創(chuàng)建一個(gè)棧幀壓入虛擬機(jī)棧中,同理,當(dāng)執(zhí)行到add方法時(shí)也是如此,如圖所示:

棧幀內(nèi)部主要由局部變量,操作數(shù)棧,動(dòng)態(tài)鏈接以及方法出口等及部分組成,接下來結(jié)合class文件了解一下,這個(gè)棧幀具體是怎么工作的。
打開class文件所在文件夾,通過javap命令查看class文件
javap -c Test.class >test.txt
代碼如圖所示:
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static int add(int, int);
Code:
0: iload_0
1: iload_1
2: iadd
3: ireturn
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: iload_1
5: iload_2
6: invokestatic #2 // Method add:(II)I
9: istore_3
10: return
}
執(zhí)行流程
iconst_1:將整數(shù)1推到操作數(shù)棧上
istore_1:棧頂元素出棧并存入局部變量表1號(hào)位
iconst_2:將整數(shù)2推到操作數(shù)棧上
istore_2:棧頂元素出棧并存入局部變量表2號(hào)位

iload_1:將局部變量表1號(hào)位元素放入棧頂
iload_2:將局部變量表2號(hào)位元素放入棧頂

invorkestatic:調(diào)用靜態(tài)方法add,該指令將彈出棧頂數(shù)據(jù)作為方法的參數(shù)并放入add棧幀中的局部變量表中

iload_0,iload_1:將局部變量表的數(shù)據(jù)壓入操作數(shù)棧

執(zhí)行到iadd的時(shí)候,操作數(shù)棧將數(shù)據(jù)相加并壓入棧,執(zhí)行完后,通過方法出口返回到main方法,并將add棧幀彈出虛擬機(jī)棧,最后通過istore指令將返回的數(shù)據(jù)存入局部變量表中

參考資料
《深入Java虛擬機(jī)》
