JVM學習筆記之棧區
本文主要內容:
棧是什麼?棧幀又是什麼?在JVM中,main方法調用say方法後,是怎麼運行的?本文將詳細講解棧。希望大家學了之後,對棧有更深的了解。
心法:在JVM中,棧管運行,堆管存儲。
棧數據結構特點:先進後出。生活中常見的case就是彈夾。最後一個壓進彈夾的子彈,最先出彈夾。
Stack棧:棧也叫棧內存,主管Java程序的運行,是在線程創建時創建,它的生命周期跟隨線程的生命周期,線程結束,棧內存也就被釋放了。對於棧來說,不存在垃圾回收問題,只要是線程一結束,該棧就over了。生命周期和線程一直的,是線程私有的。
8中基本類型的變量+對象的引用變量+實例方法都是在函數的棧內存中分配的。
棧中存儲的是什麼?
在了解棧之前,先來了解另一個概念:棧幀。
棧幀
棧幀(Stack Frame):用於支持虛擬機進行方法調用和方法執行的數據結構。它是虛擬機運行時數據區中的虛擬機棧的棧元素。
棧幀存儲了方法的局部變量表、操作數棧、動態連接和方法返回地址等信息。每個方法從調用開始至執行完成的過程,都對應這一個棧幀在虛擬機棧裡面從入棧到出棧的過程。
額,什麼叭叭叭的,說的什麼意思呢?簡單如下:
棧幀中主要保存3類數據:
本地變量(Local variables):輸入參數和輸出參數以及方法內的變量;
如上圖中的 int x,int y就是輸入參數
Int result就是輸出參數。
其中的X、Y、result都是方法內的變量
棧操作(Operand Stack):記錄出棧、入棧的操作;
棧幀數據(fram Date):包括類文件、方法等等。
棧運行的原理:
棧中的數據都是以棧幀的格式存在,棧幀是一個內存區塊,是一個數據集,是一個有關方法(Method)和運行期,數據的數據集。
當一個方法A被調用的時候,就產生了一個棧幀F1,並被壓到棧中;
A方法調用了B方法,於是產生了棧幀F2也被壓入棧中;
B方法又調用了C方法,於是產生棧幀F3,也被壓入到棧中;
依次類推。
當執行完畢後,先彈出F3棧幀,在彈出F2棧幀,在彈出F1棧幀。依次類推。
遵循」先進後出/後進先出」的原則。
代碼演示:
寫個main函數,在main方法中,調用say方法。然後查看輸出結果。
運行結果:
當程序運行到3行的時候,調用了主線程main函數,這個時候產生了棧幀F1,被壓入棧,代碼繼續向下走;
當代碼執行到第5行的時候,調用了say方法,這個時候產生了棧幀F2,發現後面還有代碼需要執行,F2就被壓入棧;
當執行第10行的時候,say方法調用了showCode方法,這個時候就產生了F3。進入方法showCode方法後,後面還有代碼,F3壓棧,繼續執行。
當執行到第17行的時候,發現沒有需要執行的了。F3就從棧裡面被彈出棧了;
接著回到say方法裡面,繼續執行,程序走到第12行的時候,發現say方法執行完成了,於是F2就被彈出棧了;
程序回到main方法中,也就是該執行第6行了,執行完第6行,當到底7行的時候,發現主函數也執行了了,於是F1就被彈出棧了;
整個線程執行完成,棧區被清空。程序結束。如下圖:
一個線程中的方法調用鏈可能會很長,很多方法都同時處於執行狀態。對於執行引擎來說,在活動線程中(爭搶到CPU執行權的),只有位於棧頂的棧幀才是有效的,成為當前棧幀(Current Stack Frame),與這個棧幀相關聯的方法稱為當前方法(Current Method)。執行引擎運行的所有字節碼指令都是只針對於當前棧幀進行操作的。
棧幀概念模型如下圖:
需要說明的是:每個方法執行的同時都會創建一個棧幀,用於存放局部變量表、操作數棧、動態連接、方法返回等等數據。每個方法從被調用至執行完成的過程,就對應著一個棧幀在虛擬機中入棧和出棧的過程。棧的大小和具體JVM的實現有關,通常在256K~756K之間,約等於1Mb左右。
棧+堆+方法區的交互關係
HotSpot是使用指針的方法來訪問對象的:
Java堆中會存放訪問類元數據的地址,reference存放的就直接是對象的地址。