參考鏈接: Java虛擬機(JVM)堆棧區域
java棧空間是一塊線程私有的內存空間,java堆和程序數據密切相關,那么java棧就是和線程執行密切相關。線程最基本的執行行為就是函數的調用。每次函數調用其實是通過java棧傳遞數據的。?
數據結構中的棧的特性:先進后出,后進先出。FIFO.?
java內存中的棧跟數據結構中的特性相似也是FIFO.但是只支持進棧和出棧操作。?
java棧中保存的主要內容是棧幀。每一次函數調用都會有對應的棧幀被壓進去java棧,執行完畢的時候被彈出java棧。如下圖所示。?
??
?
函數1對應棧幀1,函數2對應棧幀2.函數3對應棧幀3.以此類推。?
函數1調用函數2,函數2調用函數3,函數3調用函數4,以此類推。?
函數1被調用的時候棧幀1入棧,函數2被調用的時候棧幀2入棧,以此類推。?
所以最后被調用的函數在棧頂,也是最先被彈出棧的。?
每一個棧幀保存著函數的局部變量、中間運算結果等數據。?
函數返回的時候,棧幀從java棧彈出。什么時候函數返回呢?兩種情況:?
1.正常的return的時候。?
2.程序拋出異常。?
在一個棧幀內,至少包含局部變量表、操作數幀和幀數據區幾部分。?
思考的問題:沒一次函數調用生成棧幀,從而肯定會占用一定的棧空間。所以棧空間內存不足的時候,函數調用無法進行。當請求的棧深度大于最大棧深度的時候系統會拋出StackOverflowError異常。(內存溢出會在以后的章節深入的講解和匯總)?
java虛擬機制定線程的最大棧空間參數為-Xss,這個參數決定了函數調用的最大深度。?
下面一段代碼說明,是一個沒有出口的遞歸。這段代碼可能會棧溢出錯誤。如下所示:?
?
private static int count=0;
public static void recursion(){
count++;
recursion();
}
public static void main(String[] args) {
try {
recursion();
} catch (Exception e) {
System.out.println("deep of calling="+count);
e.printStackTrace();
}
}
?
?
?
使用參數-Xss128K執行代碼,結果如下:?
?
deep of calling=2020
Exception in thread "main" java.lang.StackOverflowError
at cn.xhgg.test.TestStackDeep.recursion(TestStackDeep.java:6)
?
?
?
使用參數-Xss256K執行代碼,結果如下:?
?
count=3665
Exception in thread "main" java.lang.StackOverflowError
at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77)
?
?
?
兩次內存不同對比:?
內存增大很明顯調用次數增加了。?
結論:?
函數嵌套的層數很大程度上有棧的大小決定的。棧越大,函數調用的次數就越多。?
什么因素影響函數在棧中內存大大小呢?下一個章節介紹(java虛擬機jvm局部變量表)