每當啓動一個新線程時,Java虛擬機都會爲它分配一個Java棧。Java棧以幀爲單位保存線程的運行狀態。虛擬機只會直接對Java棧執行兩種操做:以幀爲單位的壓棧和出棧。多線程
某個線程正在執行的方法被稱爲該線程的當前方法,當前方法使用的棧幀稱爲當前幀,當前方法所屬的類稱爲當前類,當前類的常量池稱爲當前常量池。在線程執行一個方法時,它會跟蹤當前類和當前常量池。此外,當虛擬機遇到棧內操做指令時,它對當前幀內數據執行操做。spa
每當線程調用一個Java方法時,虛擬機都會在該線程的Java棧中壓入一個新幀。而這個新幀天然就成爲了當前幀。在執行這個方法時,它使用這個幀來存儲參數、局部變量、中間運算結果等數據。線程
Java方法能夠以兩種方式完成。一種經過return返回的,稱爲正常返回;一種是經過拋出異常而異常終止的。無論以哪一種方式返回,虛擬機都會將當前幀彈出Java棧而後釋放掉,這樣上一個方法的幀就成爲當前幀了。code
Java幀上的全部數據都是此線程私有的。任何線程都不能訪問另外一個線程的棧數據,所以咱們不須要考慮多線程狀況下棧數據的訪問同步問題。當一個線程調用一個方法時,方法的的局部變量保存在調用線程Java棧的幀中。只有一個線程能老是訪問那些局部變量,即調用方法的線程。對象
局部變量表存放了基本數據類型、對象引用和returnAddress類型(指向一條字節碼指令的地址)。其中64位長度的long和double類型的數據會佔用2個局部變量空間(slot)(下圖1到3的緣由),其他數據類型只佔用1個。局部變量表所需的內存空間在編譯期間完成分配。每一個方法都對應一個棧幀。blog
public class StackDemo { //靜態方法 public static int runStatic(int i, long l, float f, Object o, byte b) { return 0; } //實例方法 public int runInstance(char c, short s, boolean b) { return 0; } }
其對應的局部變量表以下:內存
上方表格中,靜態方法和實例方法對應的局部變量表基本相似。但有如下區別:實例方法的表中,第一個位置存放的是當前對象的引用。get
Java沒有寄存器,全部參數傳遞都是使用操做數棧。同步
public static int add(int a,int b){ int c=0; c=a+b; return c; }
壓棧的步驟以下:虛擬機
0: iconst_0 // 0壓棧
1: istore_2 // 彈出int,存放於局部變量2
2: iload_0 // 把局部變量0壓棧
3: iload_1 // 局部變量1壓棧
4: iadd //彈出2個變量,求和,結果壓棧
5: istore_2 //彈出結果,放於局部變量2
6: iload_2 //局部變量2壓棧
7: ireturn //返回
若是計算100+98的值,那麼操做數棧的變化以下圖所示:
小對象(通常幾十個bytes),在沒有逃逸的狀況下,能夠直接分配在棧上
直接分配在棧上,能夠自動回收,減輕GC壓力
大對象或者逃逸對象沒法棧上分配