物理內存與虛擬內存之間的映射

1、用戶編制程序時使用的地址稱爲虛地址或邏輯地址,其對應的存儲空間稱爲虛存空間或邏輯地址空間;而計算機物理內存的訪問地址則稱爲實地址或物理地址,其對應的存儲空間稱爲物理存儲空間或主存空間。

2、虛擬存儲器的容量限制:主存容量+輔存(硬盤)容量。


3、物理內存:在應用中,真實存在的,插在主板內存槽上的內存條的容量的大小。從本質上來說,物理內存是代碼和數據在其中運行的窗口。

4、虛擬內存:使程序認爲它擁有連續的可用的內存(一個連續完整的地址空間),而實際上,它通常是被分隔成多個物理內存碎片,還有部分暫時存儲在外部磁盤存儲器上,在需要時進行數據交換。
若計算機運行程序或操作所需的隨機存儲器(RAM)不足時,則 Windows 會用虛擬存儲器進行補償,即拿出一部分硬盤空間來充當內存使用,這部分空間即稱爲虛擬內存,虛擬內存在硬盤上的存在形式就是 PAGEFILE.SYS這個頁面文件。它將計算機的RAM和硬盤上的臨時空間組合。將數據移入分頁文件可釋放RAM,以便完成工作。
若計算機的速率由於RAM可用空間匱乏而減緩,則可嘗試通過增加虛擬內存來進行補償。但是,計算機從RAM讀取數據的速率要比從硬盤讀取數據的速率快,因而擴增RAM容量(可加內存條)是最佳選擇。

分頁文件:硬盤上一個或者多個隱藏文件pagefile.sys,Windows用於存儲未存入內存的部分程序和數據文件。頁面文件和物理內存或隨機存取內存(RAM)構成了虛擬內存。Windows會根據需要將數據從頁面文件移至內存,或將數據從內存移至頁面文件以便爲新數據釋放內存。也叫“交換文件”。


5、虛存的訪問過程
虛存空間的用戶程序按照虛地址編程並存放在輔存(硬盤)中。程序運行時,由地址變換機構依據當時分配給該程序的實地址空間把程序的一部分調入實存。每次訪存時,首先判斷該虛地址所對應的部分是否在實存中。如果是,則進行地址轉換並用實地址訪問主存;否則,按照某種算法將輔存中的部分程序調度進內存,再按同樣的方法訪問主存。由此可見,每個程序的虛地址空間可以遠大於實地址空間,也可以遠小於實地址空間。前一種情況以提高存儲容量爲目的,後一種情況則以地址變換爲目的。後者通常出現在多用戶或多任務系統中:實存空間較大,而單個任務並不需要很大的地址空間,較小的虛存空間則可以縮短指令中地址字段的長度。

6、引入虛擬存儲技術的好處
可在較小的可用內存中執行較大的用戶程序;
可在內存中容納更多程序併發執行;
不必影響編程時的程序結構(與覆蓋技術比較);

提供給用戶可用的虛擬內存空間通常大於物理內存。


7、虛擬地址
如果CPU寄存器中的分頁標誌位被設置,那麼執行內存操作的機器指令時,CPU會自動根據頁目錄和頁表中的信息,把虛擬地址轉換成物理地址,完成該指令。比如 mov eax,004227b8h ,這是把地址004227b8h處的值賦給寄存器的彙編代碼,004227b8這個地址就是虛擬址。CPU在執行這行代碼時,發現寄存器中的分頁標誌位已經被設定,就自動完成虛擬地址到物理地址的轉換,使用物理地址取出值,完成指令。對於Intel CPU 來說,分頁標誌位是寄存器CR0的第31位,爲1表示使用分頁,爲0表示不使用分頁。對於初始化之後的 Win2k 我們觀察 CR0 ,發現第31位爲1。表明Win2k是使用分頁的。

使用了分頁機制之後,4G的地址空間被分成了固定大小的頁,每一頁或者被映射到物理內存,或者被映射到硬盤上的交換文件中,或者沒有映射任何東西。對於一般程序來說,4G的地址空間,只有一小部分映射了物理內存,大片大片的部分是沒有映射任何東西。物理內存也被分頁,來映射地址空間。對於32bit的Win2k,頁的大小是4K字節。CPU用來把虛擬地址轉換成物理地址的信息存放在叫做頁目錄和頁表的結構裏。

8、物理內存分頁
一個物理頁的大小爲4K字節,第0個物理頁從物理地址 0x00000000 處開始。由於頁的大小爲4KB,就是0x1000字節,所以第1頁從物理地址0x00001000 處開始。第2頁從物理地址 0x00002000 處開始。可以看到由於頁的大小是4KB,所以只需要32bit的地址中高20bit來尋址物理頁。
頁表:一個頁表的大小爲4K字節(32bit),放在一個物理頁中。由1024個4字節的頁表項組成。頁表中的每一項的內容(每項4個字節,32bit)高20bit用來放一個物理頁的物理地址,低12bit放着一些標誌。
頁目錄:一個頁目錄大小爲4K字節(32bit),放在一個物理頁中。由1024個4字節的頁目錄項組成。頁目錄中的每一項的內容(每項4個字節)高20bit用來放一個頁表的物理地址,低12bit放着一些標誌。

9、對於x86系統(32bit),頁目錄的物理地址放在CPU的CR3寄存器中。
一個虛擬地址轉換成物理地址的計算過程就是:處理器通過CR3找到當前頁目錄所在物理頁,取虛擬地址的高10bit,然後把這10bit左移2bit(因爲每個頁目錄項4個字節長,左移2bit相當於乘4)得到在該頁中的地址,取出該地址處PDE(4個字節),就找到了該虛擬地址對應頁表所在物理頁,取虛擬地址第12位到第21位這10位,然後把這10bit左移2bit(因爲每個頁表項4個字節長,左移2bit相當於乘4)得到在該頁中的地址,取出該地址處的PTE(4個字節),就找到了該虛擬地址對應物理頁的地址,最後加上12bit的頁內偏移得到了物理地址。

10、32bit的一個指針,可以尋址範圍0x00000000-0xFFFFFFFF,4GB大小。也就是說一個32bit的指針可以尋址整個4GB地址空間的每一個字節。一個頁表項負責4K的地址空間和物理內存的映射,一個頁表1024項,也就是負責1024*4k=4M的地址空間的映射。一個頁目錄項,對應一個頁表。一個頁目錄有1024項,也就對應着1024個頁表,每個頁表負責4M地址空間的映射。1024個頁表負責1024*4M=4G的地址空間映射。一個進程有一個頁目錄,所以以頁爲單位。頁目錄和頁表可以保證4G的地址空間中的每頁和物理內存的映射。

11、每個進程都有自己的4G地址空間,從 0x00000000-0xFFFFFFFF 。通過每個進程自己的一套頁目錄和頁表來實現。由於每個進程有自己的頁目錄和頁表,所以每個進程的地址空間映射的物理內存是不一樣的。兩個進程的同一個虛擬地址處(如果都有物理內存映射)的值一般是不同的,因爲他們往往對應不同的物理頁。

====================================================

虛擬內存: 
1.每個進程都有各自獨立的4G 字節的虛擬地址空間。4G的進程空間分爲兩部分,0~3G-1 爲用戶空間,3G~ 4G-1 爲內核空間。
2.用戶程序中使用的都是虛擬地址空間中的地址,永遠無法直接訪問實際物理地址。
3.虛擬內存到物理內存的映射由操作系統動態維護。
4.虛擬內存一方面保護了操作系統的安全,另一方面允許應用程序使用比實際物理內存更大的地址空間。
5.用戶空間中的代碼不能直接訪問內核空間中的代碼和數據,但是可以通過系統調用進入內核態,間接地與內核交互。 
6.對內存的越權訪問,或訪問未建立映射的虛擬內存(野指針、不在映射表中),將會導致段錯誤。

7. 用戶空間對應進程,進程一切換,用戶空間隨即變換。
內核空間由操作系統內核使用,不會隨進程切換而變化。
內核空間由內核根據獨立且唯一的頁表init_mm.pgd 進行映射,而用戶空間的頁表則每個進程一份。
8. 每個進程的內存空間完全獨立,因此在不同進程之間交換虛擬地址毫無意義。
9.虛擬內存到物理內存的映射,以頁(4096字節)爲單位


第一層理解

  1.每個進程都有自己獨立的4G(32位系統下)內存空間,各個進程的內存空間具有類似的結構

 

  2.一個新進程建立的時候,將會建立起自己的內存空間,此進程的數據,代碼等從磁盤拷貝到自己的進程空間,哪些數據在哪裏,都由進程控制表中的task_struct記錄,task_struct中記錄中一條鏈表,記錄中內存空間的分配情況,哪些地址有數據,哪些地址無數據,哪些可讀,哪些可寫,都可以通過這個鏈表記錄

 

  3.每個進程已經分配的內存空間,都與對應的磁盤空間映射


問題:

        計算機明明沒有那麼多內存(n個進程的話就需要n*4G)內存

        建立一個進程,就要把磁盤上的程序文件拷貝到進程對應的內存中去,對於一個程序對應的多個進程這種情況,浪費內存!


第二層理解

        1.每個進程的4G內存空間只是虛擬內存空間,每次訪問內存空間的某個地址,都需要把地址翻譯爲實際物理內存地址

        2.所有進程共享同一物理內存,每個進程只把自己目前需要的虛擬內存空間映射並存儲到物理內存上。

        3.進程要知道哪些內存地址上的數據在物理內存上,哪些不在,還有在物理內存上的哪裏,需要用頁表來記錄

        4.頁表的每一個表項分兩部分,第一部分記錄此頁是否在物理內存上,第二部分記錄物理內存頁的地址(如果在的話)

        5.當進程訪問某個虛擬地址,去看頁表,如果發現對應的數據不在物理內存中,則缺頁異常

        6.缺頁異常的處理過程,就是把進程需要的數據從磁盤上拷貝到物理內存中,如果內存已經滿了,沒有空地方了,那就找一個頁覆蓋,當然如果被覆蓋的頁曾經被修改過,需要將此頁寫回磁盤

 

總結:

優點:

1.既然每個進程的內存空間都是一致而且固定的,所以鏈接器在鏈接可執行文件時,可以設定內存地址,而不用去管這些數據最終實際的內存地址,這是有獨立內存空間的好處

2.當不同的進程使用同樣的代碼時,比如庫文件中的代碼,物理內存中可以只存儲一份這樣的代碼,不同的進程只需要把自己的虛擬內存映射過去就可以了,節省內存

3.在程序需要分配連續的內存空間的時候,只需要在虛擬內存空間分配連續空間,而不需要實際物理內存的連續空間,可以利用碎片。

 

另外,事實上,在每個進程創建加載時,內核只是爲進程“創建”了虛擬內存的佈局,具體就是初始化進程控制表中內存相關的鏈表,實際上並不立即就把虛擬內存對應位置的程序數據和代碼(比如.text .data段)拷貝到物理內存中,只是建立好虛擬內存和磁盤文件之間的映射就好(叫做存儲器映射),等到運行到對應的程序時,纔會通過缺頁異常,來拷貝數據。還有進程運行過程中,要動態分配內存,比如malloc時,也只是分配了虛擬內存,即爲這塊虛擬內存對應的頁表項做相應設置,當進程真正訪問到此數據時,才引發缺頁異常。

 

補充理解:

虛擬存儲器涉及三個概念: 虛擬存儲空間,磁盤空間,內存空間


可以認爲虛擬空間都被映射到了磁盤空間中,(事實上也是按需要映射到磁盤空間上,通過mmap),並且由頁表記錄映射位置,當訪問到某個地址的時候,通過頁表中的有效位,可以得知此數據是否在內存中,如果不是,則通過缺頁異常,將磁盤對應的數據拷貝到內存中,如果沒有空閒內存,則選擇犧牲頁面,替換其他頁面。

 

mmap是用來建立從虛擬空間到磁盤空間的映射的,可以將一個虛擬空間地址映射到一個磁盤文件上,當不設置這個地址時,則由系統自動設置,函數返回對應的內存地址(虛擬地址),當訪問這個地址的時候,就需要把磁盤上的內容拷貝到內存了,然後就可以讀或者寫,最後通過manmap可以將內存上的數據換回到磁盤,也就是解除虛擬空間和內存空間的映射,這也是一種讀寫磁盤文件的方法,也是一種進程共享數據的方法 共享內存


內存:

如果每個程序運行都直接佔用內存,那你開一個冰封王座豈不是要佔1G的內存?還能不能幹別的了。虛擬地址空間的設計簡直是神來之筆。

給每個進程分配一個4G(對32位系統來說)的虛擬地址空間。進程直接操作虛擬地址空間,讀寫數據時,纔給它調撥物理存儲器。


物理內存和虛擬內存關係:物理內存和虛擬內存對應。除OS外任何程序都不會直接訪問物理內存而是訪問虛擬內存。可把虛擬內存等同於物理內存。以後就只說內存,不再區分物理內存和虛擬內存。

頁面文件和虛擬內存關係:可把虛擬內存等同於物理內存。改變頁面文件大小可改變虛擬內存大小。詳細來說:頁面文件只是改變了物理內存的大小,當然也改變了虛擬內存的大小。(猜測:物理內存和虛擬內存的映射在大小上是1:1的。)可禁用頁面文件但不能禁用虛擬內存。

虛擬地址空間和物理地址空間對應:虛擬地址空間指的是進程的可用地址空間範圍。而物理地址空間指的是實際可用的內存空間範圍。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章