2017-10-11 128 views
7

我想與打印變量的存儲位置(地址):爲什麼用{:p}打印的內存地址比我的RAM規格大得多?

let x = 1; 
println!("{:p}", &x); 

這將打印的十六進制值0x7fff51ef6380,其十進制是140734568031104

我的電腦有16GB的RAM,那爲什麼這個數字很大? x64體系結構是否使用大間隔序列而不是簡單的1個增量來訪問內存位置?

在x86上,通常是第一個位置,從0開始,然後1,2,等等。所以你可以有最高的數字是大約4十億,因此地址數量總是等於或小於4十億。

爲什麼x64不是這種情況?

回答

11

你在這裏看到的是一個virtual memory效果。內存管理很難,當操作系統和數以百計的進程共享內存時,內存管理變得更加困難。爲了處理這種巨大的複雜性,使用了虛擬存儲器的概念。我將在這裏簡要介紹一下基本知識。這個話題要複雜得多,你也應該在其他地方閱讀它。

在大多數現代計算機中,每個進程認爲它擁有(幾乎)完整的內存空間。但進程永遠不會處理物理地址地址,但用虛擬地址爲的地址。每次進程實際從內存中讀取時,這些虛擬地址都映射到物理地址。這種地址轉換是由所謂的MMU(內存管理單元)完成的。如何映射地址的規則由操作系統設置。

當你啓動你的電腦,操作系統創建初始映射。每次啓動進程時,操作系統都會向進程添加幾片物理內存,並適當修改映射。這樣,這個過程就有記憶力。

在x86_64上,地址空間是64位寬,所以每個進程都認爲它擁有所有這些2^64地址。當然這不是真的:

  1. 世界上沒有一臺PC具有那麼多的內存。(實際上,目前大多數CPU只能使用,而只能使用280TB的RAM,因爲它們在內部只能使用48位來尋址物理內存,顯然現在這些280TB已經足夠了)。
  2. 即使你有那麼多內存,還有其他使用該內存部分的進程。

那麼當您嘗試讀取未映射的地址(在64位地址中,是絕大多數地址)時會發生什麼? MMU觸發頁面錯誤。這使得CPU通知操作系統來處理這個問題。

我的意思是說,在x86中,通常第一個位置從0開始,然後是1,2等,所以您可以擁有的最高數量是40億左右。

這是真的,但如果您的x86系統的RAM小於4GB也是如此。虛擬內存已經存在一段時間了。


所以這就是爲什麼你看到這麼大的地址的簡短總結。再次請注意,我在這裏掩蓋了許多細節。

+0

順便說一句,這是一個巧合,當前的CPU支持48位物理地址。第一代AMD64芯片支持40位物理地址,而x86-64的頁表格式可支持[52位物理地址](https://stackoverflow.com/questions/46509152/why-in-64bit-the-虛擬地址是-4比特的短48位長,相比與 - 的)。另外,虛擬地址空間實際上只有48位(並且地址必須是規範的,請參閱我的答案)。 –

+0

re:點2:不,每個進程都有自己的虛擬地址空間。這是虛擬內存的主要優點之一。內核可以保留一半用於自己的使用(例如,在內核模式下從該進程進行系統調用),但這是*全部*。一個進程總是有47個(或邏輯上爲63,而且在x86-64擴展爲真正的64位虛擬地址的情況下也是如此)。我知道你在簡化,但我認爲這一點很重要。一個進程有自己的虛擬地址空間。 –

+0

@PeterCordes關於第二點:我的意思是你所說的(我甚至提到了上面的這個優點),但是現在我可以看到我寫這個的方式,很容易被誤解。對於那個很抱歉。我會盡快修復它。謝謝! –

6

你的程序的工作原理與指針在virtual address space。 x86-64使用64位指針。這是AMD64的主要目標之一,並增加了更多的整數和XMM寄存器。你是正確的,i386只有32位的指針,每個進程只覆蓋4GB的地址空間。

0x7fff51ef6380看起來像一個堆棧指針,我的猜測是有道理的代碼。

Linux on x86-64 (for example) puts the stack near the top of the lower canonical address range:當前x86-64硬件只實現48位虛擬地址,這是防止軟件依賴它的機制。這使得地址空間在未來可以擴展而不會破壞軟件。

系統中內置RAM的數量有什麼也沒有這樣做。您會在具有128MB內存的x86-64系統(+/-堆棧address space layout randomization (ASLR))上看到(大約)相同的編號。

相關問題