1. 程式人生 > >02-JVM內存模型:虛擬機棧與本地方法棧

02-JVM內存模型:虛擬機棧與本地方法棧

system reat tac sta nts ktr 導致 lower chap

一、虛擬機棧(VM Stack)

1.1)什麽是虛擬機棧

  虛擬機棧是用於描述java方法執行的內存模型。   每個java方法在執行時,會創建一個“棧幀(stack frame)”,棧幀的結構分為“局部變量表、操作數棧、動態鏈接、方法出口”幾個部分(具體的作用會在字節碼執行引擎章節中講到,這裏只需要了解棧幀是一個方法執行時所需要數據的結構)。我們常說的“堆內存、棧內存”中的“棧內存”指的便是虛擬機棧,確切地說,指的是虛擬機棧的棧幀中的局部變量表,因為這裏存放了一個方法的所有局部變量。   方法調用時,創建棧幀,並壓入虛擬機棧;方法執行完畢,棧幀出棧並被銷毀,如下圖所示: 技術分享圖片

1.2)虛擬機棧的特點

  虛擬機棧是線程隔離的,即每個線程都有自己獨立的虛擬機棧。

1.3)虛擬機棧的StackOverflowError

  若單個線程請求的棧深度大於虛擬機允許的深度,則會拋出StackOverflowError(棧溢出錯誤)。   JVM會為每個線程的虛擬機棧分配一定的內存大小(-Xss參數),因此虛擬機棧能夠容納的棧幀數量是有限的,若棧幀不斷進棧而不出棧,最終會導致當前線程虛擬機棧的內存空間耗盡,典型如一個無結束條件的遞歸函數調用,代碼見下:
 1 /**
 2  * java棧溢出StackOverFlowError
 3  * JVM參數:-Xss128k
 4  * Created by chenjunyi on 2018/4/25.
5 */ 6 public class JavaVMStackSOF { 7 8 private int stackLength = -1; 9 10 //通過遞歸調用造成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 }
  設置單個線程的虛擬機棧內存大小為128K,執行main方法後,拋出了StackOverflow異常
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     ······

1.4)虛擬機棧的OutOfMemoryError

  不同於StackOverflowError,OutOfMemoryError指的是當整個虛擬機棧內存耗盡,並且無法再申請到新的內存時拋出的異常。
  JVM未提供設置整個虛擬機棧占用內存的配置參數。虛擬機棧的最大內存大致上等於“JVM進程能占用的最大內存(依賴於具體操作系統) - 最大堆內存 - 最大方法區內存 - 程序計數器內存(可以忽略不計) - JVM進程本身消耗內存”。當虛擬機棧能夠使用的最大內存被耗盡後,便會拋出OutOfMemoryError,可以通過不斷開啟新的線程來模擬這種異常,代碼如下:
 1 **
 2  * java棧溢出OutOfMemoryError
 3  * JVM參數:-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     //通過不斷的創建新的線程使Stack內存耗盡
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 }
  設置單個線程虛擬機棧的占用內存為2m並不斷生成新的線程,最終虛擬機棧無法申請到新的內存,拋出異常:
1 Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread

二、本地方法棧(Native Method Stack)

  本地方法棧的功能和特點類似於虛擬機棧,均具有線程隔離的特點以及都能拋出StackOverflowError和OutOfMemoryError異常。   不同的是,本地方法棧服務的對象是JVM執行的native方法,而虛擬機棧服務的是JVM執行的java方法。如何去服務native方法?native方法使用什麽語言實現?怎麽組織像棧幀這種為了服務方法的數據結構?虛擬機規範並未給出強制規定,因此不同的虛擬機實可以進行自由實現,我們常用的HotSpot虛擬機選擇合並了虛擬機棧和本地方法棧。

02-JVM內存模型:虛擬機棧與本地方法棧