1. 程式人生 > >三、虛擬記憶體 頁面置換

三、虛擬記憶體 頁面置換

現代需要執行的程式往往大到記憶體無法容納,而且必須能夠支援多個程式同時執行,及時記憶體可以滿足其中一個單獨的程式的要求,但總體來看仍然超出了記憶體大小。而交換技術由於磁碟速度的限制,也不是一個非常好的方法。

在早起計算時代(20世紀60年代)採用的方法:把程式分割成許多片段,稱為覆蓋。程式開始時,將覆蓋管理模組裝入記憶體,該模組負責在執行時動態地調入覆蓋0、1、2……並決定是獲取空閒區還是佔用已使用的區域放置要調入的覆蓋n。一般由作業系統動態地換入換出覆蓋,但是程式設計師必須把程式分割成段。這是一項非常費時且易出錯的操作。因此有人找到把全部工作交給計算機去做的辦法----虛擬記憶體。

虛擬記憶體的基本思想是:每個程序擁有自己的地址空間,這個空間被分割成多個塊,每一塊被稱作一頁或頁面。每一頁有連續的地址範圍,這些頁被對映到實體記憶體,但並不是所有的頁都必須在記憶體中才能執行程序。當程序需要用到不再實體記憶體的地址空間時,作業系統負責將缺失的部分裝入實體記憶體。

分頁

大部分虛擬記憶體系統中都使用一種稱為分頁的技術。形如程序執行指令:MOV REG,1000。這些由程序產生的地址稱為虛擬地址,他們構成了一個虛擬地址空間。在沒有虛擬記憶體的計算機上,系統直接將虛擬地址送到記憶體匯流排,讀寫操作使用具有同樣地址的實體記憶體;在使用虛擬記憶體的情況下,虛擬地址先被送到MMU(記憶體管理單元),MMU把虛擬地址對映為實體記憶體地址。

虛擬地址空間按照固定大小劃分成稱為頁面的若干單元,在實體記憶體中對應的單元稱為頁框。現有系統中頁大小一般為512位元組到64KB。

例如:在一個16位地址的計算機中,實體記憶體為32KB,程式可以有64KB的虛擬地址空間。若頁大小為4KB,則有16個虛擬頁面,8個頁框。虛擬地址空間有0至15編號的虛擬頁面,0虛擬頁面對於的虛擬地址為0~4095(4KB)並以此類推。執行指令過程:MOV REG,20500。該指令對虛擬地址20500進行操作,首先20500=20480+20,即虛擬頁面為5,從頁面5起始的第20個位元組處。要知道到該指令操作的實際實體記憶體,需要首先將虛擬頁面對映到頁框(位於實體記憶體),此時有兩種情況。(1)若虛擬頁面5能夠對映到頁框,如對應頁框為1,則對應的實體記憶體地址為4096+20=4116位元組處;(2)還有一種情況,該虛擬頁面沒有被對映到記憶體中。此時CPU將陷入到作業系統,這個陷阱稱為缺頁中斷

,作業系統將一個很少用的頁框寫入磁碟,將需要訪問的頁面讀到該頁框中,修改對映關係,然後重新啟動引起陷阱的指令。在實際的硬體中,用一個“在/不在”位來表示該虛擬頁面在記憶體中的實際存在情況。在上述的例子中,虛擬地址的前4位表示對應的虛擬頁面號,後12位表示從頁面起始位置的偏移量,這種方式十分高效,故頁面大小通常都為2的整數次冪。

頁表:

頁表是虛擬地址到實體地址最簡單的一種對映方式:虛擬地址被分成虛擬頁號(高位部分)和偏移量(低位地址)兩部分。每個虛擬頁號有一個對應的頁表項,然後由頁表項找到頁框號(若有的話)。然後把頁框號拼接到偏移量的高位端替換掉虛擬頁號,就形成了對應的實體地址。

頁表項的結構:

頁框號:用來找到對應的頁框,對映到對應的實體地址

‘在/不在’位:1表示該項有對應的頁框,0表示該虛擬頁面不再記憶體中

保護位:指出一個頁允許的訪問型別,一般有3位,分別表示是否能夠讀、寫、執行

修改位:標誌該頁面是否有過修改,如果一個頁面是被修改過(稱為“髒”的),則該頁面被重新分配頁框時必須寫回磁碟。若沒有被修改過(“乾淨”的)則簡單的丟棄即可。故也被稱為“髒”位

訪問位:幫助作業系統在發生缺頁終端時選擇要被淘汰的頁面,正在被使用的頁面更不容易被淘汰。

快取記憶體禁止位:對於一些對映到裝置暫存器而不是記憶體的頁面,假如作業系統正在等待某個I/O裝置的想要,該位保障硬體是從裝置中讀取資料而不是訪問一箇舊的快取記憶體的副本。具有獨立的I/O空間而不使用記憶體映像I/O的機器不需要這一位。

作業系統把虛擬頁面對於的磁碟地址等資訊儲存在作業系統內部的軟體表格中,故頁表不儲存不在記憶體中的頁面的磁碟地址資訊。

分頁系統中主要需要考慮兩個問題

1.       虛擬地址到實體地址的對映必須快速

2.       如果虛擬地址空間很大,頁表也會很大

每次訪問記憶體,都需要進行虛擬地址到實體地址的對映。這樣,每條指令都將至少進行一兩次或更多的頁表訪問,需要避免對映成為計算機速度的主要瓶頸。

對大而快速的頁對映的需求是構建計算機的重要約束。一種簡單的設計:使用由一組“快速硬體暫存器”組成的單一頁表。當啟動一個程序時,把儲存在記憶體中的程序頁表的部分載入到暫存器中,這樣程序執行過程中就不必再為頁表而訪問記憶體。優點是簡單且快速,缺點是頁表很大時代價很高,而且程序切換時效能降低。

另一種極端方法是整個頁表都在記憶體中,硬體只要有一個指向頁表起始位置的暫存器即可。這樣程序切換十分迅速,但每次執行指令都要一次或多次訪問記憶體,速度很慢。

分頁加速

大多數程式總是對少量的頁面進行多次訪問。即只有很少的頁表項會被反覆讀取,而其他的頁表項很少被訪問。基於這種情況,可以為計算機設定一個小型的硬體裝置,將虛擬頁面直接對映到頁框。這種裝置稱為轉換檢測緩衝區(TLB),有時也稱為相聯儲存器。通常在MMU中,包含少量表項(一般不超過64個)。

將一個虛擬地址放到MMU中進行轉換時,引進首先通過虛擬頁號與TLB中所有表項同時進行匹配(並行發生),判斷虛擬頁面是否在其中,若在則可根據保護位選擇是否直接取出頁框號;而若虛擬頁面號不在其中時,就會進行正常的頁表查詢(記憶體中),並從TLB中淘汰一個表項,用找到的新表項替代它。這樣若很快再次訪問TLB時就可以命中。有兩種不同的TLB失效:(1)是頁面訪問在記憶體中而不再TLB中,稱為軟失效。此時只需更新TLB即可,只需花費幾納秒時間;(2)頁面本身不在記憶體中,稱為硬失效,此時需要從磁碟中裝入該頁面,這個過程需要幾毫秒,是軟失效的百萬倍。

TLB也可以用軟體來管理,此時TLB表項被作業系統顯式地裝載。發生TLB訪問失效時,不再是MMU到頁表中查詢並取出需要的表項,而是生成一個TLB失效並將問題交給作業系統來解決。當TLB大到(如64個表項)可以較少失效率時,軟體管理會變得足夠有效。這樣可以使得MMU十分簡單,可以用節省的資源來改善CPU上的快取記憶體或其他效能。

大記憶體的頁表

有兩種常用的解決辦法:

(1)   多級頁表

引入多級頁表可以避免把全部頁表一直保持在記憶體中。如一個32位的虛擬地址,頁面長度為4KB,則有個頁面,即頁表有個表項。但是可能該程式實際只需要12MB的記憶體。這樣,可以用虛擬地址的前10位組成由1024個表項的頂級頁表,每個表項都表示一個4MB的虛擬地址空間,並引導找到二級頁表。由於只需要用到12MB的空間,即3個4MB的地址空間,頂級頁表只有三個表項是實際被使用的。用該虛擬地址的11位至20位這10位來引導二級頁表,則二級頁表的每個表項對於一個4KB大小的地址空間,並對映到實際的實體記憶體地址。這樣用4個1024個表項的頁表就可以定址32位的虛擬地址。

二級頁表可以擴充為三級、四級頁表,但級別越多複雜性就越大,一般不會超過三級。

(2)   倒排頁表

多級頁表可以解決32位虛擬地址空間的定址問題,但是對於64位虛擬地址就不再適用。倒排頁表使一種解決方案。在該方案中,實際記憶體中的每一個頁框有一個表項,而不是每個虛擬頁面有一個表項,表項會記錄哪一個程序的虛擬頁面定位於該頁框。

這種方案使得虛擬地址到實體地址的轉換變得困難,當程序n訪問虛擬頁面p時,需要搜尋整個倒排頁表來查詢表項(n,p),這回嚴重影響執行效率。使用TLB可以解決該問題,用TLB來記錄所有頻繁使用的頁面,地址轉換就能夠變快。但是當TLB失效時,依然需要搜尋整個倒排也表。另一個可行的方案是建立一張散列表,用虛擬地址來雜湊,所有記憶體中具有相同雜湊值得虛擬頁面被連結在一次。

倒排頁表在64位機器中很常見。