1 回答

TA貢獻2036條經驗 獲得超8個贊
每個線程都有自己的堆棧。
每當一個線程調用一個方法時,都會在堆棧內存中為該方法創建一個新塊來保存本地原始值和對該方法中其他對象的引用。這個內存塊稱為棧幀。一旦方法結束,該塊將變為未使用狀態,并將其從堆棧頂部移除。這是因為堆棧內存始終以 LIFO(后進先出)順序引用。
所以,如果你有代碼:
void go(){
int x = 1;
foo(x);
}
void foo(int y){
int z = y;
bar();
}
void bar(){
Hello h = new Hello();
}
堆??雌饋硐襁@樣:
只有這張圖片h
在范圍內。但是在bar()
方法完成后,變量y
和 都z
將在范圍內。
在內部,stack 包含局部變量 array和 操作數 stack。
在局部變量數組中存儲了方法的參數和該堆棧幀的所有局部變量。此外,如果堆棧幀表示實例方法,則局部變量數組的位置0
將是this
指向堆上對象的引用。如果方法static
在位置上,則該位置0
將是方法的第一個參數。局部變量數組的大小在編譯時確定。要查看局部變量數組,您需要查看已編譯的 Java 代碼。對于您的第一種calculate()
方法(以防萬一static
),局部變量數組將如下所示:
您可以看到變量名稱(Name
列)與其在數組中的位置(Slot
列)之間的關系。
操作數棧是用于對局部變量數組中的變量進行操作的棧。在操作數堆棧上是來自局部變量數組的變量,在您的示例中,添加并分配給其他變量,這些變量再次保存在局部變量數組中。
問題 1: 程序如何使用a
before的值b
進行操作a + b
?
因為有pop操作讀取然后從堆棧中刪除值。要添加這兩個值,您需要從操作數堆棧 (value b
) 中彈出(讀取并刪除)最后一個值。a
現在是操作數棧頂部的值。彈出(讀取并刪除)這個值(操作數堆棧現在為空)并添加這兩個值。將結果放回操作數棧。操作數?,F在只包含結果。
詳細說明:
當您調用calculate()
新的堆棧框架時,它會被創建并放在堆棧的頂部。語句int a = 15;
在內部分為 2 個步驟:
常量
15
放在操作數棧的頂部,彈出(讀取并刪除)操作數堆棧中的值(這是常量
15
)并將其保存在特定索引處的局部變量數組中。
對 重復相同的步驟int b = 25;
?,F在您有 2 個值保存在局部變量數組和空操作數堆棧中。最后一部分return a + b;
通過 4 個步驟完成:
a
將局部變量數組中的值推送(加載)到操作數堆棧,b
將值從局部變量數組推入(加載)到操作數堆?!,F在您在操作數堆棧上有兩個值。從操作數堆棧中彈出(讀取并刪除)第一個值(這是
b
值)。從操作數堆棧彈出第二個值(這是a
值)。此時操作數棧是空的。將這兩個值相加并將結果推回操作數堆?!,F在操作數棧只包含加法運算的結果。從操作數棧中彈出值并將其返回給調用此方法的任何人?,F在操作數棧是空的。
此時,由于方法已完成,棧幀從棧中移除。
問題 2: 現在我已經使用了變量a
和b
計算z
,變量如何y
能夠訪問a
并b
再次使用,因為它已經從堆棧中使用了?
因為棧幀中有一個局部變量數組,它存儲了該棧幀中定義的所有局部變量。
詳細說明:int a = 15
和int b = 25
Q1一樣。int z = a + b;
是這樣執行的:
a
將局部變量數組中的值推送(加載)到操作數堆棧,b
將值從局部變量數組推入(加載)到操作數堆棧?,F在您在操作數堆棧上有兩個值。從操作數堆棧中彈出(讀取并刪除)第一個值(這是
b
值)。從操作數堆棧彈出第二個值(這是a
值)。此時操作數棧是空的。將這兩個值相加并將結果放入操作數堆棧?,F在操作數棧只包含加法運算的結果。彈出(讀取并刪除)操作數堆棧(結果)中的值
a + b
并將其保存在特定索引處的局部變量數組中。
int y = a + b;
以與 相同的方式執行int z = a + b;
。
最后一部分return y
:
將
y
值從局部變量數組壓入操作數棧,從操作數棧中彈出值并將其返回給調用此方法的任何人。操作數?,F在是空的。
因為方法已經完成,棧幀從棧中移除。
請注意,有堆棧,它包含在多個堆棧幀中,而且在每個堆棧幀內,您都有用于該堆棧幀內操作的操作數堆棧。
添加回答
舉報