在介紹堆棧之前簡(jiǎn)單說(shuō)下JVM的內(nèi)存結(jié)構(gòu),一共分為虛擬機(jī)棧、堆、方法區(qū)、程序計(jì)數(shù)器、本地方法棧五個(gè)部分:
棧:
?線程私有,生命周期和線程生命周期相同;
?棧由一些列幀組成;
?每個(gè)方法在創(chuàng)建的執(zhí)行的時(shí)候都會(huì)創(chuàng)建一個(gè)棧幀,用來(lái)存儲(chǔ)局部變量、操作數(shù)棧、動(dòng)態(tài)鏈接、方法返回地址等;
?每個(gè)方法從調(diào)用到執(zhí)行完畢對(duì)應(yīng)一個(gè)棧幀在虛擬機(jī)棧中的入棧和出棧
堆:線程共享,在虛擬機(jī)啟動(dòng)的時(shí)候創(chuàng)建,用來(lái)存放對(duì)象實(shí)例,是GC管理的主要區(qū)域
方法區(qū):線程共享,用于存儲(chǔ)已被虛擬機(jī)加載的類信息、類型的常量池、靜態(tài)變量、字段和方法信息等
程序計(jì)數(shù)器:線程私有,是當(dāng)前線程所執(zhí)行的字節(jié)碼行號(hào)指示器,每個(gè)線程都有一個(gè)獨(dú)立的程序計(jì)數(shù)器,字節(jié)碼解釋器工作時(shí)通過(guò)改變它的值來(lái)選取下一條需要執(zhí)行的字節(jié)碼指令。
本地方法棧:線程私有,主要為虛擬機(jī)用到的native方法服務(wù),與虛擬機(jī)棧類似
簡(jiǎn)單描述下堆棧的各自特點(diǎn):
比較通俗的講就是棧是用來(lái)執(zhí)行程序的,堆主要是用來(lái)存放對(duì)象的。棧是一種具有先進(jìn)后出性質(zhì)的數(shù)據(jù)結(jié)構(gòu),也就是說(shuō)后存放的先取出。堆是一種經(jīng)過(guò)排序的樹(shù)形數(shù)據(jù)結(jié)構(gòu),每個(gè)節(jié)點(diǎn)都有一個(gè)值。通常所說(shuō)的堆的數(shù)據(jù)結(jié)構(gòu)也就是二叉堆。
SOF全稱StackOverFlowError是指棧溢出,由上面介紹可知棧是義幀為單位保存線程運(yùn)行狀態(tài)的,當(dāng)線程調(diào)用一個(gè)方法時(shí)JVM會(huì)壓入一個(gè)新的棧幀到這個(gè)線程的??臻g中,當(dāng)方法執(zhí)行結(jié)束時(shí)棧幀會(huì)出棧,但是在方法執(zhí)行過(guò)程中,這個(gè)棧幀會(huì)一直存在的。所以如果方法的嵌套調(diào)用層次太多,隨著棧幀的增加導(dǎo)致總和大于JVM設(shè)置的-Xss值就會(huì)拋出StackOverFlowError。
OOM全程OutOfMemoryError 可能分為幾種情況:
堆內(nèi)存溢出:當(dāng)需要為創(chuàng)建的對(duì)象實(shí)例化分配堆內(nèi)存空間時(shí),如果此時(shí)堆的占用已達(dá)到了設(shè)置的最大值(通過(guò) -Xmx),就會(huì)拋出OutOfMemoryError
方法區(qū)內(nèi)存溢出:在類加載器加載class文件到內(nèi)存時(shí),JVM會(huì)提取類的信息(包括:類名、訪問(wèn)修飾符、常量池、字段描述、方法描述等)到方法區(qū),而此時(shí)如果需要存儲(chǔ)這些類信息但是方法區(qū)的內(nèi)存占用又已達(dá)到最大值,就會(huì)拋出OutOfMemoryError
下面給出兩個(gè)例子可以看下:
//堆溢出例子OOM
public void heapException(){
for(;;) {
ArrayList list = new ArrayList (2000);
}
}
//棧溢出例子SOF
int count = 1;
public void stackException(){
count++;
this.stackException();
}