深入理解電腦系統結構——虛擬儲存空間

來源:互聯網
上載者:User

標籤:

虛擬儲存空間

虛擬儲存空間是硬體異常、硬體地址翻譯、主存、磁碟檔案和核心軟體的完美互動,它為每個進程提供了一個大的、一致的和私人的地址空間。通過一個很清晰的機制,虛擬儲存空間提供了三個重要的能力:

(1)它將主存看成是一個儲存在磁碟上的地址空間的快取,在主存中只儲存即時區域,並根據需要在磁碟和主存之間來回傳送資料,通過這種方式,它高效地使用了主存。

(2)它為每個進程提供了一致的地址空間,從而簡化了儲存空間管理。

(3)它保護了每個進程的地址空間不被其他進程破壞

物理和虛擬定址

物理定址

電腦系統的主存被組織成一個由M個連續的位元組大小的單元組成的數組。每位元組都有一個唯一的物理地址(Physical Address,PA)。第一個位元組的地址為0,接下來的位元組的地址為1,再下一個為2,依此類推。給定這種簡單的結構,CPU訪問儲存空間的最自然的方式就是使用物理地址,我們把這種方式稱為物理定址。

虛擬定址

使用虛擬定址時,CPU通過產生一個虛擬位址(Virtual Address,VA)來訪問主存,這個虛擬位址在被送到儲存空間之前先轉換成適當的物理地址。將一個虛擬位址轉換為物理地址的任務叫做地址翻譯(address translation)。就像異常處理一樣,地址翻譯需要CPU硬體和作業系統之間的緊密合作。CPU晶片上叫做儲存空間嵌入式管理單元(Memory Management Unit,MMU)的專用硬體,利用存放在主存中的查詢表來動態翻譯虛擬位址,該表的內容是由作業系統管理。

    MMU(memory management unit,儲存空間嵌入式管理單元),利用存放在主存中的查詢表來動態翻譯虛擬位址,該表的內容由OS管理。

 

地址空間

 

地址空間(adress space)是一個非整數地址的有序集合:{0,1,2,...}

 

如果地址空間中的整數是連續的,那麼我們說它是一個線性地址空間(linear address space)。在一個帶虛擬儲存空間的系統中,CPU從一個有N = 2 ^ n個地址空間中產生虛擬位址,這個地址空間稱為虛擬位址空間(virtual address space):{0,1,2,3,...,N-1}

 

一個地址空間的大小是由表示最大地址所需要的倍數來描述的。例如,一個包含N=2^n個地址的虛擬位址空間叫做一個n位地址空間。現在系統典型地支援32位或者64位虛擬位址空間是。

 

一個系統還有一個物理地址空間(physical addresss space),它與系統中實體儲存體器的M位元組相對應:{0,1,2,...M-1}

 

M不要求是2的冪,但是為了簡化討論,我們假設M = 2 ^ m。

 

地址空間的概念是很重要的,因為它清楚地區分了資料對象(位元組)和它們的屬性(地址)。一旦認識到了這種區別,那麼我們就可以將其推廣,允許每個資料對象有多個獨立的地址,其中每個地址都選自一個不同的地址空間(不連續的意思嗎?)。這就是虛擬儲存空間的基本思想。主存中每個位元組都有一個選自虛擬位址空間的虛擬位址和一個選自物理地址空間的物理地址。(這段沒怎麼看懂~~)

 

虛擬儲存空間作為緩衝的工具

概念上而言,虛擬儲存空間(VM)被組織為一個由存放在磁碟上N個連續的位元組大小的單元組成的數組。每個位元組都有一個唯一的虛擬位址,這個唯一的虛擬位址是作為到數組的索引的。磁碟上的數組的內容被緩衝在主存中。和儲存空間階層中其他緩衝一樣,磁碟(較低層)上的資料被分割成塊,這些塊作為磁碟和主存(較高層)之間的傳輸單元。VM系統通過將虛擬儲存空間分割稱為虛擬頁(Vitual Page,VP)的大小固定的塊來處理這個問題。每個虛擬頁的大小為P = 2 ^ n位元組。類似地,實體儲存體器被分割為物理頁(Physical Page,PP),大小也為P位元組(物理頁也稱為頁幀(page frame))。

在任意時刻,虛擬頁面的集合都分為三個不相交的子集:

  • 未分配的:VM系統還未分配(或者建立)的頁。未分配的塊沒有任何資料和它們相關聯,因此也就不佔用任何磁碟空間。(沒有調用malloc或者mmap的)
  • 緩衝的:當前緩衝在實體儲存體中的已指派頁。(已經調用malloc和mmap的,在程式中正在引用的)
  • 未緩衝的:沒有緩衝在實體儲存體器中的已指派頁。(已經調用malloc和mmap的,在程式中還沒有被引用的)

 虛擬頁0和3還沒有被分配,因此在磁碟上還不存在。虛擬頁1、4和6被緩衝在實體儲存體器中。頁2、5和7已經被分配了,但是當前並未緩衝在主存中,只存在於磁碟中。

 

頁表

同任何緩衝一樣,虛擬儲存空間系統必須有某種方法來判定一個虛擬頁是否存放在DRAM中的某個地方。如果是,系統還必須確定這個虛擬頁存放在哪個物理頁中。如果不命中,系統必須判斷這個虛擬頁存放在磁碟的哪個位置,在實體儲存體器中選擇一個犧牲頁,並將虛擬頁從磁碟拷貝到DRAM中,替換這個犧牲頁。

這些功能是由許多軟硬體聯合提供的,包括作業系統軟體,MMU(儲存空間嵌入式管理單元)中地址翻譯硬體和一個存放在實體儲存體器中叫做頁表(page table)的資料結構,頁表將虛擬頁映射到物理頁。頁表就是一個頁表條目(Page Table Entry,PTE)的數組。

 

Linux虛擬儲存空間系統

Linux為每個進程維持了一個單獨的虛擬位址空間

其中核心虛擬儲存空間包含核心中的代碼和資料結構。核心虛擬儲存空間的某些地區被映射到所有進程共用的物理頁面。例如,每個進程共用核心的代碼和全域資料結構。核心虛擬儲存空間的其他地區包含每個進程都不相同的資料。例如,頁表、核心在進程的上下文中執行代碼時使用的棧(核心棧),以及記錄虛擬位址空間當前組織的各種資料結構。


 

核心虛擬儲存空間包含核心中的代碼和資料結構。核心虛擬儲存空間的某些地區被映射到所有進程共用的物理頁面。例如,每個進程共用核心的代碼和全域資料結構

 

1、Linux虛擬儲存空間地區(Windows下也有地區的概念)

Linux將虛擬儲存空間組織成一些地區(也叫做段)的集合。一個地區(area)就是已經存在著的(已指派的)虛擬儲存空間的連續片(chunk),這些頁是以某種方式相關聯的。例如,程式碼片段、資料區段、堆、共用庫段,以及使用者棧都不同的地區。每個存在的虛擬頁面儲存在某個地區中,而不屬於某個地區的虛擬頁是不存在的,並且不能被進程引用。地區的概念很重要,因為它允許虛擬位址空間有間隙。核心不用記錄那些不存在的虛擬頁,而這樣的頁也不佔用儲存空間。磁碟或者核心本身的任何額外資源

核心為系統中的每個進程維護一個單獨的任務結構(原始碼中的task_struct)。任務結構中的元素包含或者指向核心運行該進程所需要的所有資訊(例如,PID,指向使用者棧的指標、可執行檔目標檔案的名字以及程式計數器)。

 

task_struct中的一個條目指向mm_struct,它描述了虛擬儲存空間中的目前狀態。其中pgd指向第一級頁表(頁全域目錄)的基址,而mmap指向一個vm_area_struct(地區結構)的鏈表,其中每個vm_area_structs都描述了當前虛擬位址空間的一個地區(area)。當核心運行這個進程時,它就將pgd存放在CR3控制寄存器中。

一個具體地區結構包含下面的欄位:

  • vm_start:指向這個地區的起始處。
  • vm_end:指向這個地區的結束處。
  • vm_prot:描述這個地區的內包含的所有頁的讀寫許可許可權。
  • vm_flags:描述這個地區內頁面是與其他進程共用的,還是這個進程私人的(還描述了其他一些資訊)。
  • vm_next:指向鏈表中下一個地區結構。
 2 、linux缺頁異常處理假設MMU在試圖翻譯某個虛擬位址A時,觸發了一個缺頁。這個異常導致控制轉移到核心的缺頁處理常式,處理常式隨後就執行下面的步驟:1)虛擬位址A是合法的嗎?換句話說,A在某個地區結構定義的地區內嗎?為了回答這個問題,缺頁處理常式搜尋地區結構的鏈表,把A和每個地區結構中的vm_start和vm_end做比較。如果這個指令時不合法的,那麼缺頁處理常式就觸發一個段錯誤(說明這個虛擬位址還沒有映射),從而終止這個進程。這個情況在圖9-28中標識為“1”2)試圖進行的儲存空間訪問是否合法?換句話說,進程是否有讀、寫或者執行這個地區內頁面的許可權?例如,這個缺頁是不是由一條試圖對這個程式碼片段裡的唯讀頁面進行寫操作的儲存指令造成的?這個缺頁是不是因為一個運行在使用者模式中的進程試圖從核心虛擬儲存空間中讀取字造成的?如果試圖進行的訪問時不合法的,那麼缺頁處理常式會觸發一個保護異常,從而終止這個進程。這種情況標識為"2"3)此刻,核心知道了這個缺頁是由於對合法的虛擬位址進行合法的操作造成的。它是這樣來處理這個缺頁的:選擇一個犧牲頁面,如果這個犧牲頁面被修改過,那麼就將它交換出去,換入新的頁面並更新頁表。當缺頁處理常式返回時,CPU重新啟動引起缺頁的指令,這條指令將再次發送A到MMU。這次,MMU就能正常地翻譯A,而不會產生缺頁中斷了。  儲存空間映射(Windows下也有類似的機制,名叫記憶體映射)  Linux(以及其他一些形式的Unix)通過將一個虛擬儲存空間地區與一個磁碟上的對象(object)關聯起來,以初始化這個虛擬儲存空間地區的內容,這個過程稱為儲存空間映射(memory mapping)。虛擬儲存空間地區可以映射到兩種類型的對象的一種:(1) Unix檔案上的普通檔案:一個地區可以映射到一個普通磁碟檔案的連續部分,例如一個可執行目標檔案。檔案區(section)被分成頁大小的片,每一片包含一個虛擬頁面的初始化內容。因為按需進行頁面高度,所以這些虛擬頁面沒有實際進行實體儲存體器,直到CPU第一次引用到頁面(即發射一個虛擬位址,落在地址空間這個頁面的範圍之內)。如果地區檔案區要大,那麼就用零來填充這個地區的餘下部分。 (2) 匿名檔案:一個地區也可以映射到一個匿名檔案,匿名檔案是由核心建立的,包含的全是二進位零。CPU第一次引用這樣一個地區內的虛擬頁面時,核心就在實體儲存體器中找到一個合適的犧牲頁面,如果該頁面被修改過,就將這個頁面換出來,用二進位零覆蓋犧牲頁面並更新頁表,將這個頁面標記為是駐留在儲存空間中的。注意在磁碟和儲存空間之間沒有實際的資料傳送。因為這個原因,映射到匿名檔案的地區中的頁面有時也叫做請求二進位零的頁(demand-zero page)。無論在哪種情況下,一旦一個虛擬頁面被初始化了, 它就在一個由核心維護的專門的分頁檔(swap file)之間換來換去。分頁檔也叫做交換空間(swap space)或者交換地區(swap area)。需要意識到的很重要的一點, 在任何時刻,交換空間都限制著當前運行著的進程能夠分配的虛擬頁面的總數再看共用對象一個對象可以被映射到虛擬儲存的一個地區,要麼作為共用對象,要麼作為私人對象。如果一個進程將一個共用對象映射到它的虛擬位址空間的一個地區內,那麼這個進程對這個地區的任何寫操作,對於那些也把這個共用對象映射到它們虛擬儲存空間的其他進程而言也是可見的。而且,這此變化也會反映在磁碟上的原始對象中。(IPC的一種方式)另一方面,對一個映射到私人對象的地區做的改變,對於其他進程來說是不可見的,並且進程對這個地區所做的任何寫操作都不會反映在磁碟上的對象中。一個映射到共用對象的虛擬儲存空間地區叫做共用地區。類似地,也有私人地區。 

共用對象的關鍵點在於即使對象被映射到了多個共用地區,實體儲存體器也只需要存放共用對象的一個拷貝。

一個共用對象(注意,物理頁面不一定是連續的。)


 

私人對象是使用一種叫做寫時拷貝(copy-on-write)的巧妙技術被映射到虛擬儲存空間中的。對於每個映射私人對象的進程,相應私人地區的頁表條目都被標記為唯讀,並且地區結構被標記為私人的寫時拷貝。


 

再看fork函數

當fork函數被當前進程調用時,核心為新進程建立各種資料結構,並分配給它一個唯一的PID。為了給這個新進程建立虛擬儲存空間,它建立了當前進程的mm_struct、地區結構和頁表的原樣拷貝。它將兩個進程中的每個頁面都為標記唯讀,並將兩個進程中的每個地區結構都標記為私人的寫時拷貝。

當fork在新進程中返回時,新進程現在的虛擬儲存空間剛好和調用fork時存在的虛擬儲存空間相同。當這兩個進程中的任一個後來進行寫操作時,寫時拷貝機制就會建立新頁面,因此,也就為每個進程保持了私人地址空間的抽象概念。

 

再看execve函數

假設運行在當前進程中的程式執行了如下的調用:

execve("a.out",NULL,NULL) ;

execve函數在當前進程中載入並運行包含在可執行目標檔案a.out中的程式,用a.out程式有效地替代了當前程式。載入並運行a.out需要以下幾個步驟:

 

  • 刪除已存在的使用者地區。刪除當前進程虛擬位址使用者部分中的已存在的地區結構。
  • 映射私人地區。為新程式的文本、資料、bss和棧地區建立新的地區結構。所有這些新的地區都是私人的、寫時拷貝的。文本和資料區域被映射為a.out檔案中的文本和資料區。bss地區是請求二進位零的,映射到匿名檔案,其大小包含在a.out中。棧和堆地區也是請求二進位零的。
  • 映射共用地區。如果a.out程式與共用對象(或目標)連結,比如標準C庫libc.so,那麼這些對象都是動態連結到這個程式的,然後再映射到使用者虛擬位址空間中的共用地區內。
  • 設定程式計數器(PC)。execve做的最後一件事情就是設定當前進程上下文中的程式計數器,使之指向文本地區的進入點。
下一次調度這個進程時,它將從這個進入點開始執行。Linux將根據需要換入代碼和資料頁面。  使用mmap函數的使用者級儲存空間映射 [cpp] view plaincopy 
  1. #include<unistd.h>  
  2. #include<sys/mman.h>  
  3.   
  4.   
  5. void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset) ;  
  6.                 //返回:若成功時則為指向映射地區的指標,若出錯則為MAP_FAILED(-1)  

mmap函數要求核心建立一個新的虛擬儲存空間地區是,最好是從地址start開始的一個地區,並將檔案描述符fd指定的對象的一個連續的片(chunk)映射到這個新地區。連續的對象片大小為length位元組,從距檔案開始處位移量為offset位元組的地方開始。start地址僅僅是一個暗示,通常被定義為NULL。




[cpp] view plaincopy 
  1. munmap函數刪除虛擬儲存空間的地區:  
  2. #include<unistd.h>  
  3. #include<sys/mman.h>  
  4.   
  5.   
  6. int munmap(void *start,size_t length);  
  7.     //返回:若成功則為0,若出錯則為-1  
   虛擬儲存空間是對主存的一個抽象。支援虛擬儲存空間的處理器通過使用一種叫做虛擬定址的間接形式來引用主存。處理器產生一個虛擬位址,在被發送到主存之前,這個地址被翻譯成一個物理地址。從虛擬位址空間到物理地址空間的地址翻譯要求硬體和軟體緊密合作。專門的硬體通過使用頁表來翻譯虛擬位址,而頁表的內容是由作業系統提供的。 虛擬儲存空間提供三個重要的功能。第一,它在主存中自動緩衝最近使用的存放磁碟上的虛擬位址空間的內容。虛擬儲存空間緩衝中的塊叫做頁。對磁碟上頁的引用會觸發缺頁,缺頁將控制轉移到作業系統中的一個缺頁處理常式。缺頁處理常式將頁面從磁碟拷貝到主存緩衝,如果必要,將寫回被驅逐的頁。第二,虛擬儲存空間簡化了儲存空間管理,進而又簡化了連結、在進程間共用資料、進程的儲存空間分配以及程式載入。最後,虛擬儲存空間通過在每條頁表條目中加入保護位,從而簡化了儲存空間保護。 地址翻譯的過程必須和系統中所有的硬體緩衝的操作整合在一起。大多數頁表條目位於L1快取中,但是一個稱為TLB的頁表條目的片上快取,通常會消除訪問在L1上的頁表條目的開銷。 

 

深入理解電腦系統結構——虛擬儲存空間

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.