Java開發中每當我們在程序中使用new生成一個對象對象的引用存放在棧裡而對象是存放在堆裡的可以看出棧在Java核心的重要位置今天我們就繼續深入Java核心這個系列為您介紹Java中的棧局部變量及其之間的關系
Java中的棧
每當啟用一個線程時JVM就為他分配一個Java棧棧是以幀為單位保存當前線程的運行狀態某個線程正在執行的方法稱為當前方法當前方法使用的棧幀稱為當前幀當前方法所屬的類稱為當前類當前類的常量池稱為當前常量池當線程執行一個方法時它會跟蹤當前常量池
每當線程調用一個Java方法時JVM就會在該線程對應的棧中壓入一個幀這個幀自然就成了當前幀當執行這個方法時它使用這個幀來存儲參數局部變量中間運算結果等等
Java棧上的所有數據都是私有的任何線程都不能訪問另一個線程的棧數據所以我們不用考慮多線程情況下棧數據訪問同步的情況
像方法區和堆一樣Java棧和幀在內存中也不必是連續的幀可以分布在連續的棧裡也可以分布在堆裡
Java棧的組成元素——棧幀
棧幀由三部分組成局部變量區操作數棧幀數據區局部變量區和操作數棧的大小要視對應的方法而定他們是按字長計算的但調用一個方法時它從類型信息中得到此方法局部變量區和操作數棧大小並據此分配棧內存然後壓入Java棧
局部變量區 局部變量區被組織為以一個字長為單位從開始計數的數組類型為shortbyte和char的值在存入數組前要被轉換成int值而long和double在數組中占據連續的兩項在訪問局部變量中的long或double時只需取出連續兩項的第一項的索引值即可如某個long值在局部變量區中占據的索引時項取值時指令只需取索引為的long值即可
下面就看個例子好讓大家對局部變量區有更深刻的認識這個圖來自《深入JVM》
以下是引用片段
public static int runClassMethod(int ilong lfloat fdouble dObject obyte b) {
return ;
}
public int runInstanceMethod(char cdouble dshort sboolean b) {
return ;
}
上面代碼片的方法參數和局部變量在局部變量區中的存儲結構如下圖
上面這個圖沒什麼好說的大家看看就會懂但是在這個圖裡有一點需要注意
runInstanceMethod的局部變量區第一項是個reference(引用)它指定的就是對象本身的引用也就是我們常用的this但是在runClassMethod方法中沒這個引用那是因為runClassMethod是個靜態方法
操作數棧和局部變量區一樣操作數棧也被組織成一個以字長為單位的數組但和前者不同的是它不是通過索引來訪問的而是通過入棧和出棧來訪問的可把操作數棧理解為存儲計算時臨時數據的存儲區域下面我們通過一段簡短的程序片段外加一幅圖片來了解下操作數棧的作用
以下是引用片段
int a = ;
int b = ;
int c = a+b;
從圖中可以得出操作數棧其實就是個臨時數據存儲區域它是通過入棧和出棧來進行操作的
幀數據區除了局部變量區和操作數棧外Java棧幀還需要一些數據來支持常量池解析正常方法返回以及異常派發機制這些數據都保存在Java棧幀的幀數據區中
當JVM執行到需要常量池數據的指令時它都會通過幀數據區中指向常量池的指針來訪問它
除了處理常量池解析外幀裡的數據還要處理Java方法的正常結束和異常終止如果是通過return正常結束則當前棧幀從Java棧中彈出恢復發起調用的方法的棧如果方法又返回值JVM會把返回值壓入到發起調用方法的操作數棧
為了處理Java方法中的異常情況幀數據區還必須保存一個對此方法異常引用表的引用當異常拋出時JVM給catch塊中的代碼如果沒發現方法立即終止然後JVM用幀區數據的信息恢復發起調用的方法的幀然後再發起調用方法的上下文重新拋出同樣的異常
棧的整個結構
在前面就描述過棧是由棧幀組成每當線程調用一個Java方法時JVM就會在該線程對應的棧中壓入一個幀而幀是由局部變量區操作數棧和幀數據區組成那在一個代碼塊中棧到底是什麼形式呢?下面是我從《深入JVM》中摘抄的一個例子大家可以看看
代碼片段
執行過程中的三個快照
上面所給的圖只想說明兩件事情我們也可用此來理解Java中的棧
只有在調用一個方法時才為當前棧分配一個幀然後將該幀壓入棧
幀中存儲了對應方法的局部數據方法執行完對應的幀則從棧中彈出並把返回結果存儲在調用方法的幀的操作數棧中
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26394.html