2015-09-03 61 views
4

我已經將值分配給值類型說爲例是否值類型變量違反堆疊的LIFO性質

int i=0; 
int j=1; 

由於int是存儲器在堆棧分配如下值類型變量(推我的價值和j堆棧):

|_|<-- stack top 
|1|<--j value 
|0|<--i value 

我有一個關於這個分配幾個疑惑:

  • 如果我在這段時間執行i+=1堆棧分配的變化是什麼?
  • 它是如何可能流行的i值,而不坡平j
  • ,如果我重新分配的i,則該值將被存儲在堆棧頂部,就在這個時候發生了什麼以前分配的值:
+0

你能解釋一下這個問題:在第0個位置上的數值現在應該是0 ,現在應該在第1個位置上加上應該分配的數值? –

+1

你爲什麼認爲第二行不只是使用「第零位」?如果你說「我是第零的位置」,爲什麼我突然跳到第一位? – John3136

回答

0

你需要考慮到以下信息:

  1. C#只是在編譯語言時間,和.NET CLR負責人類製造者在程序執行期間從.NET代碼中讀取機器代碼。
  2. 現代CPU有一套集中使用的寄存器,避免每次操作都需要堆棧。

因此,在你的代碼中,.NET CLR將最有可能的地方i和j變量到寄存器,最有可能會安排代碼,這樣,只有當沒有更多的寄存器使用,臨時變量將被放置在堆棧上。

但是,該堆棧不是一個普通的LIFO結構。訪問堆棧變量可以使用EBP和ESP寄存器作爲基本偏移量。

0

當您創建並讀取它們時,局部變量不會被推入並彈出。

在該方法的開始是代碼來創建一個堆棧框架,爲本地變量騰出空間。這是通過移動堆棧指針來在該堆棧上創建一個該方法可以使用的內存區域來完成的。

即使變量的作用域小於方法,每個局部變量在起始位置都有一個固定的位置。在執行該方法期間,堆棧框架不會改變。

|      | 
| More stack data  | 
|      | 
+------------------------+ 
| Method return address | 
+------------------------+ 
| i      | Stack frame 
| j      | 
+------------------------+ 
<--- stack pointer 

通常,bp寄存器被設置爲指向堆棧幀,所以[bp + 0]訪問i[bp + 4]訪問j

在該方法結束時,有代碼通過將堆棧指針放回去除堆棧幀,以便彈出下一個返回地址。(請注意,這是一個實現細節,JIT編譯器可能會使用一個寄存器來存儲變量而不是空間到堆棧幀中,當閉包進入圖片時它會改變一些東西,但它可以作爲一個理解局部變量如何工作的出發點。)

2

你的心智模式被嚴重破壞,你直接從字面上理解「堆棧」這個詞。只有當一個方法調用另一個方法時,處理器堆棧纔像堆棧一樣。在一個方法中,參數和局部變量存儲在stack frame中。它是免費尋址的,不推動或彈出。總是作爲基址指針寄存器或堆棧指針寄存器的偏移量。 EBP採用32位代碼,RSP採用64位代碼。堆棧幀的大小取決於局部變量的數量。只需通過減小棧指針的大小來「分配」它。只需通過恢復堆棧指針即可「銷燬」。

如果將它建模爲C#Stack<object[]>數據結構,則會更接近。

Wikipedia article應該有助於澄清概念。