1. 程式人生 > >Java記憶體區域——Java虛擬機器棧

Java記憶體區域——Java虛擬機器棧

Java虛擬機器棧這塊區域的功能,描述的是Java方法執行動態記憶體模型。就是說,一個方法的執行以及執行完畢,那麼,整個的記憶體模型就是在Java虛擬機器棧中。

每個方法執行都會建立一個棧幀,伴隨著方法從建立到執行完成。棧幀是用於儲存方法可執行的區域性變量表、運算元棧、動態連結,方法出口等。每次方法執行,棧幀都會伴隨著一個進棧以及出棧的這麼一個過程。我們可以簡單的描述一下這個過程,這是我們的Java虛擬機器棧

棧記憶體是一端開口,先進後出的原則,每一個方法要執行,首先要建立一個棧幀

每一個方法執行都要建立一個棧幀,那麼,這個棧幀裡面所儲存的就是區域性變量表、運算元棧、動態連結、方法出口等,我們建立好了棧幀之後,方法就開始進棧,進棧就開始執行,那麼,在執行的過程中,比如說它呼叫了另外的方法,那麼,另外這個方法也需要建立一個棧幀,接著,它所呼叫的那個方法進棧

那麼,這個方法就開始執行了,那麼,這個方法執行到方法出口之後,這個方法就執行完畢了,方法執行完畢之後,這個棧幀就出棧了,出棧之後就銷燬了

然後接著執行它

那麼,這個方法繼續執行,一直執行完畢,出棧

這就是一個方法執行的過程。也就是說,Java虛擬機器棧描述的就是Java方法執行的動態記憶體模型。

什麼是區域性變量表呢?

區域性變量表所需的記憶體空間其實是在編譯期就完成了分配,當進入到一個方法的時候,這個方法需要在棧中分配多少記憶體其實是固定了的,那麼在方法執行期間,這個記憶體大小是不會改變的。

大家這裡可能有疑問了,比如引用型別,比如我們這裡有一個User物件,這個物件裡面有一個name屬性,那麼,我們在執行期間可能給這個name指定值

這個name屬性是String型別

我們可能會給name這個屬性指定值,那麼,name屬性值的長度肯定是不固定的,那麼這個時候,它的記憶體區域是不會變化的嗎?為什麼在方法執行期間是不會改變區域性變量表的大小?其實,我們在區域性變量表中所引用的只是一個物件的引用,後面會講,物件的建立會建立到堆記憶體中,而區域性變量表所儲存的是一個物件的引用,那麼,這個物件的引用,這個大小是不會改變的,所以,在方法執行期間區域性變量表的大小是不會改變的

接下來我們說一下Java虛擬機器棧的大小的問題。

如果虛擬機器棧放不下棧幀了怎麼辦?即虛擬機器棧中放滿了棧,但是依然去呼叫方法,這個時候,我們就遇到了我們所熟悉的StackOverFlowError,這叫棧記憶體溢位

,這個異常其實是我們如果寫一個遞迴呼叫的方法,就非常常見這個異常。我們來模擬一下棧記憶體溢位,我們知道每一個方法的執行都會進棧

我們通過記憶體模型來分析一下這個報錯的原因,首先有一個Java虛擬機器棧

首先

呼叫tes()方法,tes()方法進棧

這個方法進棧之後,首先執行第六行程式碼,然後接著執行第七行程式碼,執行第七行程式碼的時候,Java虛擬機發現又執行了一個方法,接著這個方法又進棧,所以,不停的進棧,方法之間不停的呼叫,不停的進棧,那麼,我們就會發現

棧記憶體就會出現溢位的問題,那麼,也就導致了StackOverflowError這個異常的丟擲。如果我們把這個棧的大小改成非常大,就是,我們不限定這個棧的深度的大小,那麼,這個時候它會不停的去申請,如果不限定棧大小的話,如果當棧的記憶體區域已經大於Java虛擬機器設定的記憶體,或者說,已經超出了我們機器本身的記憶體,已經申請不下來記憶體的時候,就會丟擲OutofmemeryError,就是記憶體溢位。