1.為什么要有虛擬內存
在早期的計算機中,是沒有虛擬內存的概念的。我們要運行一個程序,會把程序全部裝入內存,然后運行。
當運行多個程序時,經常會出現以下問題:
1)進程地址空間不隔離,沒有權限保護。
由于程序都是直接訪問物理內存,所以一個進程可以修改其他進程的內存數據,
甚至修改內核地址空間中的數據。
2)內存使用效率低
當內存空間不足時,要將其他程序暫時拷貝到硬盤,然后將新的程序裝入內存運行。
由于大量的數據裝入裝出,內存使用效率會十分低下。
3)程序運行的地址不確定
因為內存地址是隨機分配的,所以程序運行的地址也是不確定的。
2.虛擬地址和物理地址
對于32位系統,尋址指針為4字節,對應的虛擬地址空間為0-2^32,即0-4G。
對于64位系統,尋址指針為8字節,對應的虛擬地址空間為0-2^64,即0-16G。
要注意的是,這個地址空間是虛擬的,并非實際存在的。
linux內核把虛擬地址空間分為兩部分:用戶進程空間,內核進程空間。
如下如所示:
更多linux內核視頻教程文本資料免費獲取后臺私信【內核】。
在緩存原理中,換入/換出的數據以塊為最小單位。在內存管理時,也是地址空間的最小單位。
虛擬地址空間劃分為多個固定大小的虛擬頁(VP),物理地址空間(DRAM內存)劃分為多個固定大小的物理頁(PP),
虛擬頁和物理頁的大小是一樣的,通常為4KB。
虛擬頁和物理頁存在著以下關系:
虛擬頁和磁盤文件映射,然后緩存到物理頁。
根據是否映射,是否緩存,可以將虛擬頁的狀態分為以下三種:
1)未映射的頁
即虛擬頁沒有映射到磁盤文件
2)未緩存的頁
虛擬頁映射到了磁盤文件,但是沒有緩存到物理頁,也就是內存上。
3)緩存的頁
虛擬頁映射到了磁盤文件,并且緩存到物理頁
如下圖所示:
3.虛擬地址的工作原理
對于進程來說,使用的都是虛擬地址。每個進程維護一個單獨的頁表。何為頁表?
頁表是一種數組結構,存放著各虛擬頁的狀態,是否映射,是否緩存。
1)數組的索引號,表示虛擬頁號
2)數組的值
若為null,表示未映射的頁
若非null,第一位表示有效位,為1,表明緩存的頁;為0,表明未緩存的頁面。
其余位表示緩存到的物理頁號。
頁表結構圖如下:
進程執行時,當需要訪問虛擬地址中存放的值時,步驟如下:
1)CPU會先找到虛擬地址所在的虛擬頁(VP3),根據頁表,找出頁表中第3條的值。
判斷有效位,為1,DRMA緩存命中,獲根據物理頁號,找到物理頁中的內容,返回。
2)若有效位為0,產生缺頁異常,調用內核缺頁異常處理程序。
它會選擇一個物理頁(如PP4),作為犧牲頁,將該頁的內容刷新到磁盤文件。然后,把VP3映射的磁盤文件,緩存到該物理頁。
頁表中的第3條,有效位變1,同時,物理頁號表號變為PP4。
3)缺頁異常處理完畢后,返回中斷前的指令,重新執行,此時緩存命中,執行1)
4)將找到的內容映射到高速緩存,CPU從高速緩存中獲取該值,結束。
4.使用虛擬地址需要注意的問題
1)磁盤和主存傳送頁的活動叫做頁面調度。頁面調度會引起磁盤流量,如果程序的局部性不好,會頻繁進行頁面調度,叫做“緩存顛簸”。
操作系統會在內存中分配一塊交換區作為緩沖區,來加速頁面的調度。
2)一級頁表占用的空間是比較大的,根據按需調度的原則,一般使用的是多級頁表,即一級頁表指向二級頁表,這樣大大壓縮了頁表的大小。
5.地址翻譯
地址翻譯指的是DRAM緩存命中時,由虛擬地址找到物理地址的過程。
該過程是完全由硬件來完成的。
1)CPU有一個專門的頁表基地址寄存器(PTBR)指向當前頁表的基地址,快速定位到該進程的頁表。
2)根據虛擬頁號,找到虛擬地址在頁表的值。
3)根據值中的物理頁號,找到物理地址。
6.Linux中的虛擬內存機制
Linux把虛擬內存劃分成區域area的集合,一個area包括連續的多個頁。
area的數據結構如下所示:
1)內核為每個進程維護了一個單獨的任務結果task_struct
2)task_struct的mm指針,指向了mm_struct,該結構描述虛擬內存的運行狀態。
3)mm_struct的pgd指針指向進程的一級頁表的基地址。
mmap指針,指向vm_area_struct鏈表。
4)vm_area_struct描述area的結構,vm_start表示area的開始位置,vm_end表示area的結束位置,vm_prot表示area內的頁的讀寫權限,vm_flags表示area內的頁面是進程私有還是共享,vm_next指向下一個area節點。
在Linux中,當發生缺頁異常時,步驟如下:
1)缺頁異常程序,檢查虛擬地址在哪個area內。
2)訪問的虛擬頁若沒有讀寫權限,則觸發一個保護異常,終止進程。
3)選擇犧牲頁,刷新到磁盤,從磁盤加載缺失的內容到物理頁,更新頁表。
7.Linux虛擬內存需要注意的問題
內存映射機制:初始化虛擬內存區域時,會把虛擬內存和磁盤文件對象對應起來。
由于內存映射機制,一個磁盤文件對象可被多個進程共享訪問,也可被多個進程私有訪問。
當共享訪問時,一個進程對該對象的修改會顯示到其他進程。
當私有訪問時,修改時會產生保護故障,內核會拷貝這個私有對象,修改的是這個新對象,其他進程指向的是原來的對象。
fork函數是說明內存映射機制很好的例子:
fork函數會創建帶有獨立虛擬地址空間的新進程,內核會把當前進程的虛擬內存中數據結構復制一份給新進程。虛擬內存area包括共享區域和私有區域,新建的進程對私有區域做修改時,會觸發寫時拷貝,為新進程維護私有的虛擬地址空間。
8.虛擬地址作用總結
1)虛擬內存管理可以控制物理內存的訪問權限
訪問的虛擬頁若沒有讀寫權限,則觸發一個保護異常,終止進程。
2)虛擬內存讓每個進程有獨立的地址空間
對于私有區域來說,當不同進程對該區域做修改時,會觸發寫時拷貝,為新進程維護私有的虛擬地址空間。
3)VA到PA的映射會給分配和釋放內存帶來方便。
物理內存不連續的地址,可映射到連續的虛擬內存地址。
4)內存效率高
使用了頁面調度,不會造成大量的數據裝入裝出。