一、虛擬機(jī)棧(VM Stack)
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-475693.html
1.1)什么是虛擬機(jī)棧
虛擬機(jī)棧是用于描述java方法執(zhí)行的內(nèi)存模型。
每個(gè)java方法在執(zhí)行時(shí),會(huì)創(chuàng)建一個(gè)“棧幀(stack frame)”,棧幀的結(jié)構(gòu)分為“局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口”幾個(gè)部分(具體的作用會(huì)在字節(jié)碼執(zhí)行引擎章節(jié)中講到,這里只需要了解棧幀是一個(gè)方法執(zhí)行時(shí)所需要數(shù)據(jù)的結(jié)構(gòu))。我們常說(shuō)的“堆內(nèi)存、棧內(nèi)存”中的“棧內(nèi)存”指的便是虛擬機(jī)棧,確切地說(shuō),指的是虛擬機(jī)棧的棧幀中的局部變量表,因?yàn)檫@里存放了一個(gè)方法的所有局部變量。
方法調(diào)用時(shí),創(chuàng)建棧幀,并壓入虛擬機(jī)棧;方法執(zhí)行完畢,棧幀出棧并被銷毀,如下圖所示:
?
1.2)虛擬機(jī)棧的特點(diǎn)
虛擬機(jī)棧是線程隔離的,即每個(gè)線程都有自己獨(dú)立的虛擬機(jī)棧。
1.3)虛擬機(jī)棧的StackOverflowError
若單個(gè)線程請(qǐng)求的棧深度大于虛擬機(jī)允許的深度,則會(huì)拋出StackOverflowError(棧溢出錯(cuò)誤)。
JVM會(huì)為每個(gè)線程的虛擬機(jī)棧分配一定的內(nèi)存大?。?Xss參數(shù)),因此虛擬機(jī)棧能夠容納的棧幀數(shù)量是有限的,若棧幀不斷進(jìn)棧而不出棧,最終會(huì)導(dǎo)致當(dāng)前線程虛擬機(jī)棧的內(nèi)存空間耗盡,典型如一個(gè)無(wú)結(jié)束條件的遞歸函數(shù)調(diào)用,代碼見(jiàn)下:
復(fù)制代碼
?1 /**
?2 * java棧溢出StackOverFlowError
?3 * JVM參數(shù):-Xss128k
?4 * Created by chenjunyi on 2018/4/25.
?5 */
?6 public class JavaVMStackSOF {
?7?
?8 private int stackLength = -1;
?9?
10 //通過(guò)遞歸調(diào)用造成StackOverFlowError
11 public void stackLeak() {
12 stackLength++;
13 stackLeak();
14 }
15?
16 public static void main(String[] args) {
17 JavaVMStackSOF oom = new JavaVMStackSOF();
18 try {
19 oom.stackLeak();
20 } catch (Throwable e) {
21 System.out.println("Stack length:" + oom.stackLength);
22 e.printStackTrace();
23 }
24 }
25?
26 }
復(fù)制代碼
設(shè)置單個(gè)線程的虛擬機(jī)棧內(nèi)存大小為128K,執(zhí)行main方法后,拋出了StackOverflow異常
復(fù)制代碼
1 Stack length:983
2 java.lang.StackOverflowError
3 at com.manayi.study.jvm.chapter2._02_JavaVMStackSOF.stackLeak(_02_JavaVMStackSOF.java:14)
4 at com.manayi.study.jvm.chapter2._02_JavaVMStackSOF.stackLeak(_02_JavaVMStackSOF.java:15)
5 at com.manayi.study.jvm.chapter2._02_JavaVMStackSOF.stackLeak(_02_JavaVMStackSOF.java:15)
6 ······
復(fù)制代碼
1.4)虛擬機(jī)棧的OutOfMemoryError
不同于StackOverflowError,OutOfMemoryError指的是當(dāng)整個(gè)虛擬機(jī)棧內(nèi)存耗盡,并且無(wú)法再申請(qǐng)到新的內(nèi)存時(shí)拋出的異常。
JVM未提供設(shè)置整個(gè)虛擬機(jī)棧占用內(nèi)存的配置參數(shù)。虛擬機(jī)棧的最大內(nèi)存大致上等于“JVM進(jìn)程能占用的最大內(nèi)存(依賴于具體操作系統(tǒng)) - 最大堆內(nèi)存 - 最大方法區(qū)內(nèi)存 - 程序計(jì)數(shù)器內(nèi)存(可以忽略不計(jì)) - JVM進(jìn)程本身消耗內(nèi)存”。當(dāng)虛擬機(jī)棧能夠使用的最大內(nèi)存被耗盡后,便會(huì)拋出OutOfMemoryError,可以通過(guò)不斷開(kāi)啟新的線程來(lái)模擬這種異常,代碼如下:
復(fù)制代碼
?1 **
?2 * java棧溢出OutOfMemoryError
?3 * JVM參數(shù):-Xss2m
?4 * Created by chenjunyi on 2018/4/25.
?5 */
?6 public class JavaVMStackOOM {
?7?
?8 private void dontStop() {
?9 while (true) {
10 }
11 }
12?
13 //通過(guò)不斷的創(chuàng)建新的線程使Stack內(nèi)存耗盡
14 public void stackLeakByThread() {
15 while (true) {
16 Thread thread = new Thread(() -> dontStop());
17 thread.start();
18 }
19 }
20?
21 public static void main(String[] args) {
22 JavaVMStackOOM oom = new _03_JavaVMStackOOM();
23 oom.stackLeakByThread();
24 }
25?
26 }
復(fù)制代碼
設(shè)置單個(gè)線程虛擬機(jī)棧的占用內(nèi)存為2m并不斷生成新的線程,最終虛擬機(jī)棧無(wú)法申請(qǐng)到新的內(nèi)存,拋出異常:
1 Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
二、本地方法棧(Native Method Stack)
本地方法棧的功能和特點(diǎn)類似于虛擬機(jī)棧,均具有線程隔離的特點(diǎn)以及都能拋出StackOverflowError和OutOfMemoryError異常。
不同的是,本地方法棧服務(wù)的對(duì)象是JVM執(zhí)行的native方法,而虛擬機(jī)棧服務(wù)的是JVM執(zhí)行的java方法。如何去服務(wù)native方法?native方法使用什么語(yǔ)言實(shí)現(xiàn)?怎么組織像棧幀這種為了服務(wù)方法的數(shù)據(jù)結(jié)構(gòu)?虛擬機(jī)規(guī)范并未給出強(qiáng)制規(guī)定,因此不同的虛擬機(jī)實(shí)可以進(jìn)行自由實(shí)現(xiàn),我們常用的HotSpot虛擬機(jī)選擇合并了虛擬機(jī)棧和本地方法棧。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-475693.html
?
到了這里,關(guān)于JVM 虛擬機(jī)棧介紹的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!