2012-01-08 38 views
2

我對此很新,所以如果問題沒有意義,我會提前道歉。變量如何尋址RAM?

如果我是正確的,c#中的int是4個字節。如果我有這樣的說法:

int x; 

我會認爲這是佔用4個字節的內存。如果每個內存地址空間是1個字節,那麼這將佔用4個地址插槽?如果是這樣,x如何映射到四個地址位置?

+0

那麼,這是一個很好的問題,但它有一個很長的答案。我會看到我能保持多短。 – riwalk 2012-01-08 16:42:59

+0

我同意,我認爲這對SO會更好。 – Puppy 2012-01-08 16:58:31

回答

11

如果我有聲明int x;我會認爲這是佔用4個字節的內存。 x如何映射到四個字節的地址?

首先,邁克是正確的。 C#是專門設計的,所以你不必擔心這個東西。讓記憶管理者幫你照顧它;它做得很好。

假設你確實想看看香腸是如何爲你自己的薰香製作的:你的假設是不合理的。此聲明不需要需要導致任何內存消耗。如果它確實導致內存消耗,則int將消耗四個字節的內存。

本地變量(*)可以使用兩種方法消耗內存。第一個是,它從來沒有使用過:

void M() 
{ 
    int x; 
} 

編譯器可以是足夠聰明,知道X不會被寫入或讀取,它可以完全合法地省略。顯然它沒有記憶。

它可以不佔用內存的第二種方式是如果抖動選擇註冊本地。它可以專門爲該局部變量分配一個機器寄存器。該變量然後沒有地址與它相關聯,因爲顯然寄存器沒有地址。(**)

假設本地確實佔用內存,抖動負責跟蹤該內存的位置。

如果本地是一個非常正常的本地,那麼抖動會使堆棧指針碰撞四個字節,從而在堆棧上保留四個字節。然後它會將這四個字節與本地相關聯。

如果本地是匿名函數的封閉外部本地,迭代器塊的本地或異步方法的本地,則C#編譯器將生成本地作爲類的字段;抖動會要求垃圾收集器分配類實例,抖動會將本地與垃圾收集器與該實例關聯的內存緩衝區起始處的特定偏移量關聯起來。

所有這些都是實現細節可能隨時更改;不要依賴它。 (*)我們知道這是一個局部變量,因爲您說這是一個聲明。現場聲明不是聲明

(**)如果不安全的代碼需要本地地址,顯然它不能被註冊。

2

你真的不應該擔心這些事情,因爲在C#中沒有辦法編寫可以利用這些信息的代碼。

但是,如果您必須知道,在我們指示CPU訪問x的內容時,在機器代碼級別,將使用這四個字節中第一個的地址來引用它。執行此操作的機器指令還將包含有關要訪問多少個字節的信息,在本例中爲四個。

5

有很多(我的意思是很多),可以說這個。你打的各種主題是stack,symbol table,memory management,memory hierarchy,...我可以繼續。

但是,因爲你是新的,我會盡力給出一個更容易的答案:當你在程序中創建一個變量(如int)

,你告訴編譯器預留空間在該數據的內存中。一個int是4個字節,所以4 連續的字節被保留。您所指的內存位置僅指向開頭。事後知道長度是4個字節。

現在內存位置(在您提供的情況下)並不像變量那樣真正保存。每當有一個命令需要x時,該命令就會被一個顯式獲取該內存位置的命令替代。換句話說,地址保存在程序的「代碼」部分,而不是「數據」部分。

這只是一個真的,真的是高概覽。希望它有幫助。

+0

如果它是一個局部變量,它可能會留在寄存器中而不是被分散到堆棧中。 – 2012-01-08 20:15:06

+0

@ SK邏輯,哦好點。忘記看看這個因素。 – riwalk 2012-01-09 04:53:08

1

如果int x;是在一個函數中聲明的,那麼這個變量將被分配到堆棧中,而不是堆或全局內存中。編譯器符號表中x的地址將引用四字節整數的第一個字節。然而,由於它位於堆棧上,所記住的地址將是堆棧上的偏移地址,而不是物理地址。然後該變量將通過使用來自當前堆棧指針的偏移量的指令被引用。

假設32位運行時間,堆棧上的偏移量將對齊,所以地址是4個字節的倍數,即偏移量將以0,4,8或0x0c結尾。此外,由於80x86族是little-endian,整數的第一個字節將是最不重要的,並且第四個字節將是最重要的,例如,十進制值1,000,000將被存儲爲四字節0x40 0x42 0x0f 0x00。