java虛擬機器 jvm 出入java棧 棧空間記憶體分配

weixin_33858249發表於2016-04-02

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區域性變數表)



相關文章