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

1、虛擬機棧(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

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

  本地方法棧的功能和特色相似於虛擬機棧,均具備線程隔離的特色以及都能拋出StackOverflowError和OutOfMemoryError異常。
  不一樣的是,本地方法棧服務的對象是JVM執行的native方法,而虛擬機棧服務的是JVM執行的java方法。如何去服務native方法?native方法使用什麼語言實現?怎麼組織像棧幀這種爲了服務方法的數據結構?虛擬機規範並未給出強制規定,所以不一樣的虛擬機實能夠進行自由實現,咱們經常使用的HotSpot虛擬機選擇合併了虛擬機棧和本地方法棧。
相關文章
相關標籤/搜索