1. 程式人生 > >《計算機作業系統》總結三(記憶體管理)

《計算機作業系統》總結三(記憶體管理)

記憶體管理

包括記憶體管理和虛擬記憶體管理

記憶體管理包括記憶體管理概念、交換與覆蓋、連續分配管理方式和非連續分配管理方式(分頁管理方式、分段管理方式、段頁式管理方式)。

虛擬記憶體管理包括虛擬記憶體概念、請求分頁管理方式、頁面置換演算法、頁面分配策略、工作集和抖動。

3.1 記憶體管理的概念

記憶體管理(Memory Management)是作業系統設計中最重要和最複雜的內容之一。雖然計算機硬體一直在飛速發展,記憶體容量也在不斷增長,但是仍然不可能將所有使用者程序和系統所需要的全部程式和資料放入主存中,所以作業系統必須將記憶體空間進行合理地劃分和有效地動態分配。作業系統對記憶體的劃分和動態分配
,就是記憶體管理的概念。

有效的記憶體管理在多道程式設計中非常重要,不僅方便使用者使用儲存器、提高記憶體利用率,還可以通過虛擬技術從邏輯上擴充儲存器。

記憶體管理的功能有:
  • 記憶體空間的分配與回收:由作業系統完成主儲存器空間的分配和管理,使程式設計師擺脫儲存分配的麻煩,提高程式設計效率。
  • 地址轉換:在多道程式環境下,程式中的邏輯地址與記憶體中的實體地址不可能一致,因此儲存管理必須提供地址變換功能,把邏輯地址轉換成相應的實體地址。
  • 記憶體空間的擴充:利用虛擬儲存技術或自動覆蓋技術,從邏輯上擴充記憶體。
  • 儲存保護:保證各道作業在各自的儲存空間內執行,.互不干擾。

在進行具體的記憶體管理之前,需要了解程序執行的基本原理和要求

程式裝入和連結

建立程序首先要將程式和資料裝入記憶體。將使用者源程式變為可在記憶體中執行的程式,通常需要以下幾個步驟:
  • 編譯:由編譯程式將使用者原始碼編譯成若干個目標模組
  • 連結:由連結程式將編譯後形成的一組目標模組,以及所需庫函式連結在一起,形成一個完整的裝入模組
  • 裝入:由裝入程式將裝入模組裝入記憶體執行

這三步過程如圖3-1所示。


圖3-1  對使用者程式的處理步驟
程式的連結有以下三種方式
  • 靜態連結:在程式執行之前,先將各目標模組及它們所需的庫函式連結成一個完整的可執行程式,以後不再拆開。
  • 裝入時動態連結:將使用者源程式編譯後所得到的一組目標模組,在裝入記憶體時,釆用邊裝入邊連結的連結方式。
  • 執行時動態連結:對某些目標模組的連結,是在程式執行中需要該目標模組時,才對它進行的連結。其優點是便於修改和更新,便於實現對目標模組的共享。

記憶體的裝入模組在裝入記憶體時,同樣有以下三種方式

1) 絕對裝入。在編譯時,如果知道程式將駐留在記憶體的某個位置,編譯程式將產生絕對地址的目的碼。絕對裝入程式按照裝入模組中的地址,將程式和資料裝入記憶體。由於程式中的邏輯地址與實際記憶體地址完全相同,故不需對程式和資料的地址進行修改。

絕對裝入方式只適用於單道程式環境。另外,程式中所使用的絕對地址,可在編譯或彙編時給出,也可由程式設計師直接賦予。而通常情況下在程式中釆用的是符號地址,編譯或彙編時再轉換為絕對地址。

2) 可重定位裝入。在多道程式環境下,多個目標模組的起始地址通常都是從0開始,程式中的其他地址都是相對於起始地址的,此時應釆用可重定位裝入方式。根據記憶體的當前情況,將裝入模組裝入到記憶體的適當位置。裝入時對目標程式中指令和資料的修改過程稱為重定位,地址變換通常是在裝入時一次完成的,所以又稱為靜態重定位,如圖3-2(a) 所示。


圖3-2  重定向型別
靜態重定位的特點是在一個作業裝入記憶體時,必須分配其要求的全部記憶體空間,如果沒有足夠的記憶體,就不能裝入該作業。此外,作業一旦進入記憶體後,在整個執行期間不能在記憶體中移動,也不能再申請記憶體空間。

3) 動態執行時裝入,也稱為動態重定位,程式在記憶體中如果發生移動,就需要釆用動態的裝入方式。裝入程式在把裝入模組裝入記憶體後,並不立即把裝入模組中的相對地址轉換為絕對地址,而是把這種地址轉換推遲到程式真正要執行時才進行。因此,裝入記憶體後的所有地址均為相對地址。這種方式需要一個重定位暫存器的支援,如圖3-2(b)所示。

動態重定位的特點是可以將程式分配到不連續的儲存區中;在程式執行之前可以只裝入它的部分程式碼即可投入執行,然後在程式執行期間,根據需要動態申請分配記憶體;便於程式段的共享,可以向用戶提供一個比儲存空間大得多的地址空間。

邏輯地址空間與實體地址空間

編譯後,每個目標模組都是從0號單元開始編址,稱為該目標模組的相對地址(或邏輯地址)。 當連結程式將各個模組連結成一個完整的可執行目標程式時,連結程式順序依次按各個模組的相對地址構成統一的從0號單元開始編址的邏輯地址空間。使用者程式和程式設計師只需知道邏輯地址,而記憶體管理的具體機制則是完全透明的,它們只有系統程式設計人員才會涉及。不同程序可以有相同的邏輯地址,因為這些相同的邏輯地址可以對映到主存的不同位置。

實體地址空間是指記憶體中物理單元的集合,它是地址轉換的最終地址,程序在執行時執行指令和訪問資料最後都要通過實體地址從主存中存取。裝入程式將可執行程式碼裝入記憶體時,必須通過地址轉換將邏輯地址轉換成實體地址,這個過程稱為地址重定位

記憶體保護

記憶體分配前,需要保護作業系統不受使用者程序的影響,同時保護使用者程序不受其他使用者程序的影響。通過釆用重定位暫存器和界地址暫存器來實現這種保護。重定位暫存器含最小的實體地址值,界地址暫存器含邏輯地址值。每個邏輯地址值必須小於界地址暫存器;記憶體管理機構動態地將邏輯地址與界地址暫存器進行比較,如果未發生地址越界,則加上重定位暫存器的值後對映成實體地址,再送交記憶體單元,如圖3-3所示。

當CPU排程程式選擇程序執行時,派遣程式會初始化重定位暫存器和界地址暫存器。每一個邏輯地址都需要與這兩個暫存器進行核對,以保證作業系統和其他使用者程式及資料不被該程序的執行所影響


圖3-3  重定位和界地址暫存器的硬體支援

3.2 記憶體覆蓋與記憶體交換

覆蓋與交換技術是在多道程式環境下用來擴充記憶體的兩種方法。

記憶體覆蓋

早期的計算機系統中,主存容量很小,雖然主存中僅存放一道使用者程式,但是儲存空間放不下使用者程序的現象也經常發生,這一矛盾可以用覆蓋技術來解決。

覆蓋的基本思想是:由於程式執行時並非任何時候都要訪問程式及資料的各個部分(尤其是大程式),因此可以把使用者空間分成一個固定區和若干個覆蓋區。將經常活躍的部分放在固定區,其餘部分按呼叫關係分段。首先將那些即將要訪問的段放入覆蓋區,其他段放在外存中,在需要呼叫前,系統再將其調入覆蓋區,替換覆蓋區中原有的段

覆蓋技術的特點是打破了必須將一個程序的全部資訊裝入主存後才能執行的限制,但當同時執行程式的程式碼量大於主存時仍不能執行。

記憶體交換

交換(對換)的基本思想是,把處於等待狀態(或在CPU排程原則下被剝奪執行權利)的程式從記憶體移到輔存,把記憶體空間騰出來,這一過程又叫換出;把準備好競爭CPU執行的程式從輔存移到記憶體,這一過程又稱為換入。中級排程就是釆用交換技術。

例如,有一個CPU釆用時間片輪轉排程演算法的多道程式環境。時間片到,記憶體管理器將剛剛執行過的程序換出,將另一程序換入到剛剛釋放的記憶體空間中。同時,CPU排程器可以將時間片分配給其他已在記憶體中的程序。每個程序用完時間片都與另一程序交換。理想情況下,記憶體管理器的交換過程速度足夠快,總有程序在記憶體中可以執行。

有關交換需要注意以下幾個問題:
  • 交換需要備份儲存,通常是快速磁碟。它必須足夠大,並且提供對這些記憶體映像的直接訪問。
  • 為了有效使用CPU,需要每個程序的執行時間比交換時間長,而影響交換時間的主要是轉移時間。轉移時間與所交換的記憶體空間成正比。
  • 如果換出程序,必須確保該程序是完全處於空閒狀態。
  • 交換空間通常作為磁碟的一整塊,且獨立於檔案系統,因此使用就可能很快。
  • 交換通常在有許多程序執行且記憶體空間吃緊時開始啟動,而系統負荷降低就暫停。
  • 普通的交換使用不多,但交換策略的某些變種在許多系統中(如UNIX系統)仍發揮作用。

交換技術主要是在不同程序(或作業)之間進行,而覆蓋則用於同一個程式或程序中。由於覆蓋技術要求給出程式段之間的覆蓋結構,使得其對使用者和程式設計師不透明,所以對於主存無法存放使用者程式的矛盾,現代作業系統是通過虛擬記憶體技術來解決的,覆蓋技術則已成為歷史;而交換技術在現代作業系統中仍具有較強的生命力。

3.3 記憶體連續分配管理方式

連續分配方式,是指為一個使用者程式分配一個連續的記憶體空間。它主要包括單一連續分配、固定分割槽分配和動態分割槽分配。

單一連續分配

記憶體在此方式下分為系統區和使用者區,系統區僅提供給作業系統使用,通常在低地址部分;使用者區是為使用者提供的、除系統區之外的記憶體空間。這種方式無需進行記憶體保護。

這種方式的優點是簡單、無外部碎片,可以釆用覆蓋技術,不需要額外的技術支援。缺點是隻能用於單使用者、單任務的作業系統中,有內部碎片,儲存器的利用率極低。

固定分割槽分配

固定分割槽分配是最簡單的一種多道程式儲存管理方式,它將使用者記憶體空間劃分為若干個固定大小的區域,每個分割槽只裝入一道作業。當有空閒分割槽時,便可以再從外存的後備作業佇列中,選擇適當大小的作業裝入該分割槽,如此迴圈。


圖3-4  固定分割槽分配的兩種方法
固定分割槽分配在劃分分割槽時,有兩種不同的方法,如圖3-4所示。
  • 分割槽大小相等:用於利用一臺計算機去控制多個相同物件的場合,缺乏靈活性。
  • 分割槽大小不等:劃分為含有多個較小的分割槽、適量的中等分割槽及少量的大分割槽。

為便於記憶體分配,通常將分割槽按大小排隊,併為之建立一張分割槽說明表,其中各表項包括每個分割槽的起始地址、大小及狀態(是否已分配),如圖3-5(a)所示。當有使用者程式要裝入時,便檢索該表,以找到合適的分割槽給予分配並將其狀態置為”已分配”;未找到合適分割槽則拒絕為該使用者程式分配記憶體。儲存空間的分配情況如圖3-5(b)所示。

這種分割槽方式存在兩個問題:一是程式可能太大而放不進任何一個分割槽中,這時使用者不得不使用覆蓋技術來使用記憶體空間;二是主存利用率低,當程式小於固定分割槽大小時,也佔用了一個完整的記憶體分割槽空間,這樣分割槽內部有空間浪費,這種現象稱為內部碎片。

固定分割槽是可用於多道程式設計最簡單的儲存分配,無外部碎片,但不能實現多程序共享一個主存區,所以儲存空間利用率低。固定分割槽分配很少用於現在通用的作業系統中,但在某些用於控制多個相同物件的控制系統中仍發揮著一定的作用。


圖3-5  固定分割槽說明表和記憶體分配情況

動態分割槽分配

動態分割槽分配又稱為可變分割槽分配,是一種動態劃分記憶體的分割槽方法。這種分割槽方法不預先將記憶體劃分,而是在程序裝入記憶體時,根據程序的大小動態地建立分割槽,並使分割槽的大小正好適合程序的需要。因此係統中分割槽的大小和數目是可變的。


圖3-6動態分割槽
如圖3-6所示,系統有64MB記憶體空間,其中低8MB固定分配給作業系統,其餘為使用者可用記憶體。開始時裝入前三個程序,在它們分別分配到所需空間後,記憶體只剩下4MB,程序4無法裝入。在某個時刻,記憶體中沒有一個就緒程序,CPU出現空閒,作業系統就換出程序2,換入程序4。由於程序4比程序2小,這樣在主存中就產生了一個6MB的記憶體塊。之後CPU又出現空閒,而主存無法容納程序2,作業系統就換出程序1,換入程序2。

動態分割槽在開始分配時是很好的,但是之後會導致記憶體中出現許多小的記憶體塊。隨著時間的推移,記憶體中會產生越來越多的碎片(圖3-6中最後的4MB和中間的6MB,且隨著程序的換入/換出,很可能會出現更多更小的記憶體塊),記憶體的利用率隨之下降。
這些小的記憶體塊稱為外部碎片,指在所有分割槽外的儲存空間會變成越來越多的碎片,這與固定分割槽中的內部碎片正好相對。克服外部碎片可以通過緊湊(Compaction)技術來解決,就是作業系統不時地對程序進行移動和整理。但是這需要動態重定位暫存器的支援,且相對費時。緊湊的過程實際上類似於Windows系統中的磁碟整理程式,只不過後者是對外存空間的緊湊。

在程序裝入或換入主存時,如果記憶體中有多個足夠大的空閒塊,作業系統必須確定分配哪個記憶體塊給程序使用,這就是動態分割槽的分配策略,考慮以下幾種演算法:
  • 首次適應(First  Fit)演算法:空閒分割槽以地址遞增的次序連結。分配記憶體時順序查詢,找到大小能滿足要求的第一個空閒分割槽。
  • 最佳適應(Best  Fit)演算法:空閒分割槽按容量遞增形成分割槽鏈,找到第一個能滿足要求的空閒分割槽。
  • 最壞適應(Worst  Fit)演算法:又稱最大適應(Largest Fit)演算法,空閒分割槽以容量遞減的次序連結。找到第一個能滿足要求的空閒分割槽,也就是挑選出最大的分割槽。
  • 鄰近適應(Next  Fit)演算法:又稱迴圈首次適應演算法,由首次適應演算法演變而成。不同之處是分配記憶體時從上次查詢結束的位置開始繼續查詢。

在這幾種方法中,首次適應演算法不僅是最簡單的,而且通常也是最好和最快的。在UNIX 系統的最初版本中,就是使用首次適應演算法為程序分配記憶體空間,其中使用陣列的資料結構 (而非連結串列)來實現。不過,首次適應演算法會使得記憶體的低地址部分出現很多小的空閒分割槽,而每次分配查詢時,都要經過這些分割槽,因此也增加了查詢的開銷。

鄰近適應演算法試圖解決這個問題,但實際上,它常常會導致在記憶體的末尾分配空間(因為在一遍掃描中,記憶體前面部分使用後再釋放時,不會參與分配),分裂成小碎片。它通常比首次適應演算法的結果要差。

最佳適應演算法雖然稱為“最佳”,但是效能通常很差,因為每次最佳的分配會留下很小的難以利用的記憶體塊,它會產生最多的外部碎片。

最壞適應演算法與最佳適應演算法相反,選擇最大的可用塊,這看起來最不容易產生碎片,但是卻把最大的連續記憶體劃分開,會很快導致沒有可用的大的記憶體塊,因此效能也非常差。

Kunth和Shore分別就前三種方法對記憶體空間的利用情況做了模擬實驗,結果表明:

首次適應演算法可能比最佳適應法效果好,而它們兩者一定比最大適應法效果好。另外注意,在演算法實現時,分配操作中最佳適應法和最大適應法需要對可用塊進行排序或遍歷查詢,而首次適應法和鄰近適應法只需要簡單查詢;回收操作中,當回收的塊與原來的空閒塊相鄰時(有三種相鄰的情況,比較複雜),需要將這些塊合併。在演算法實現時,使用陣列或連結串列進行管理。除了記憶體的利用率,這裡的演算法開銷也是作業系統設計需要考慮的一個因素。

表3-1三種記憶體分割槽管理方式的比較
作業道數 內部
碎片
外部
碎片
硬體支援 可用空
間管理
解決碎
片方法
解決空
間不足
提高作
業道數
單道連續
分配
1 界地址暫存器、越界
檢查機構
-- -- 覆蓋 交換
多道固定
連續分配
<=N
(使用者空間劃
為N塊)
  1. 上下界暫存器、越界檢查機構
  2. 基地址暫存器、長度暫存器、動態地址轉換機構
-- --
多道可變連續分配
  • 陣列
  • 連結串列
緊湊

以上三種記憶體分割槽管理方法有一共同特點,即使用者程序(或作業)在主存中都是連續存放的。這裡對它們進行比較和總結,見表3-1。

3.4 記憶體非連續分配管理方式

非連續分配允許一個程式分散地裝入到不相鄰的記憶體分割槽中,根據分割槽的大小是否固定分為分頁儲存管理方式和分段儲存管理方式。

分頁儲存管理方式中,又根據執行作業時是否要把作業的所有頁面都裝入記憶體才能執行分為基本分頁儲存管理方式和請求分頁儲存管理方式。下面介紹基本分頁儲存管理方式。

基本分頁儲存管理方式

固定分割槽會產生內部碎片,動態分割槽會產生外部碎片,這兩種技術對記憶體的利用率都比較低。我們希望記憶體的使用能儘量避免碎片的產生,這就引入了分頁的思想把主存空間劃分為大小相等且固定的塊,塊相對較小,作為主存的基本單位。每個程序也以塊為單位進行劃分,程序在執行時,以塊為單位逐個申請主存中的塊空間。

分頁的方法從形式上看,像分割槽相等的固定分割槽技術,分頁管理不會產生外部碎片。但它又有本質的不同點:塊的大小相對分割槽要小很多,而且程序也按照塊進行劃分,程序執行時按塊申請主存可用空間並執行。這樣,程序只會在為最後一個不完整的塊申請一個主存塊空間時,才產生主存碎片,所以儘管會產生內部碎片,但是這種碎片相對於程序來說也是很小的,每個程序平均只產生半個塊大小的內部碎片(也稱頁內碎片)。

1) 分頁儲存的幾個基本概念

①頁面和頁面大小。程序中的塊稱為頁(Page),記憶體中的塊稱為頁框(Page Frame,或頁幀)。外存也以同樣的單位進行劃分,直接稱為塊(Block)。程序在執行時需要申請主存空間,就是要為每個頁面分配主存中的可用頁框,這就產生了頁和頁框的一一對應。

為方便地址轉換,頁面大小應是2的整數冪。同時頁面大小應該適中,如果頁面太小,會使程序的頁面數過多,這樣頁表就過長,佔用大量記憶體,而且也會增加硬體地址轉換的開銷,降低頁面換入/換出的效率;頁面過大又會使頁內碎片增大,降低記憶體的利用率。所以頁面的大小應該適中,考慮到耷間效率和時間效率的權衡。

②地址結構。分頁儲存管理的邏輯地址結構如圖3-7所示。


圖3-7  分頁儲存管理的地址結構
地址結構包含兩部分:前一部分為頁號P,後一部分為頁內偏移量W。地址長度為32 位,其中0~11位為頁內地址,即每頁大小為4KB;12~31位為頁號,地址空間最多允許有2^20頁。

③頁表。為了便於在記憶體中找到程序的每個頁面所對應的物理塊,系統為每個程序建立一張頁表,記錄頁面在記憶體中對應的物理塊號,頁表一般存放在記憶體中。

在配置了頁表後,程序執行時,通過查詢該表,即可找到每頁在記憶體中的物理塊號。可見,頁表的作用是實現從頁號到物理塊號的地址對映,如圖3-8所示。


圖3-8  頁表的作用

2) 基本地址變換機構

地址變換機構的任務是將邏輯地址轉換為記憶體中實體地址,地址變換是藉助於頁表實現的。圖3-9給出了分頁儲存管理系統中的地址變換機構。


圖3-9  分頁儲存管理的地址變換機構
在系統中通常設定一個頁表暫存器(PTR),存放頁表在記憶體的始址F和頁表長度M。程序未執行時,頁表的始址和長度存放在程序控制塊中,當程序執行時,才將頁表始址和長度存入頁表暫存器。設頁面大小為L,邏輯地址A到實體地址E的變換過程如下:
  1. 計算頁號P(P=A/L)和頁內偏移量W (W=A%L)。
  2. 比較頁號P和頁表長度M,若P >= M,則產生越界中斷,否則繼續執行。
  3. 頁表中頁號P對應的頁表項地址 = 頁表起始地址F + 頁號P * 頁表項長度,取出該頁表項內容b,即為物理塊號。
  4. 計算E=b*L+W,用得到的實體地址E去訪問記憶體。

以上整個地址變換過程均是由硬體自動完成的。

例如,若頁面大小L為1K位元組,頁號2對應的物理塊為b=8,計算邏輯地址A=2500 的實體地址E的過程如下:P=2500/1K=2,W=2500%1K=452,查詢得到頁號2對應的物理塊的塊號為 8,E=8*1024+452=8644。

下面討論分頁管理方式存在的兩個主要問題
  • 每次訪存操作都需要進行邏輯地址到實體地址的轉換,地址轉換過程必須足夠快,否則訪存速度會降低;
  • 每個程序引入了頁表,用於儲存對映機制,頁表不能太大,否則記憶體利用率會降低。

3) 具有快表的地址變換機構

由上面介紹的地址變換過程可知,若頁表全部放在記憶體中,則存取一個數據或一條指令至少要訪問兩次記憶體:一次是訪問頁表,確定所存取的資料或指令的實體地址,第二次才根據該地址存取資料或指令。顯然,這種方法比通常執行指令的速度慢了一半。

為此,在地址變換機構中增設了一個具有並行查詢能力的高速緩衝儲存器——快表,又稱聯想暫存器(TLB),用來存放當前訪問的若干頁表項,以加速地址變換的過程。與此對應,主存中的頁表也常稱為慢表,配有快表的地址變換機構如圖3-10所示。


圖3-10  具有快表的地址變換機構
在具有快表的分頁機制中,地址的變換過程:
  • CPU給出邏輯地址後,由硬體進行地址轉換並將頁號送入快取記憶體暫存器,並將此頁號與快表中的所有頁號進行比較。
  • 如果找到匹配的頁號,說明所要訪問的頁表項在快表中,則直接從中取出該頁對應的頁框號,與頁內偏移量拼接形成實體地址。這樣,存取資料僅一次訪存便可實現。
  • 如果沒有找到,則需要訪問主存中的頁表,在讀出頁表項後,應同時將其存入快表,以便後面可能的再次訪問。但若快表已滿,則必須按照一定的演算法對舊的頁表項進行替換。

注意:有些處理機設計為快表和慢表同時查詢,如果在快表中查詢成功則終止慢表的查詢。

一般快表的命中率可以達到90%以上,這樣,分頁帶來的速度損失就降低到10%以下。快表的有效性是基於著名的區域性性原理,這在後面的虛擬記憶體中將會具體討論。

4) 兩級頁表

第二個問題:由於引入了分頁管理,程序在執行時不需要將所有頁調入記憶體頁框中,而只要將儲存有對映關係的頁表調入記憶體中即可。但是我們仍然需要考慮頁表的大小。 以32 位邏輯地址空間、頁面大小4KB、頁表項大小4B為例,若要實現程序對全部邏輯地址空間的對映,則每個程序需要2^20,約100萬個頁表項。也就是說,每個程序僅頁表這一項就需要4MB主存空間,這顯然是不切實際的。而即便不考慮對全部邏輯地址空間進行對映的情況,一個邏輯地址空間稍大的程序,其頁表大小也可能是過大的。 以一個40MB的程序為例,頁表項共40KB,如果將所有頁表項內容儲存在記憶體中,那麼需要10個記憶體頁框來儲存整個頁表。整個程序大小約為1萬個頁面,而實際執行時只需要幾十個頁面進入記憶體頁框就可以執行,但如果要求10個頁面大小的頁表必須全部進入記憶體,這相對實際執行時的幾十個程序頁面的大小來說,肯定是降低了記憶體利用率的;從另一方面來說,這10頁的頁表項也並不需要同時儲存在記憶體中,因為大多數情況下,對映所需要的頁表項都在頁表的同一個頁面中。

將頁表對映的思想進一步延伸,就可以得到二級分頁:將頁表的10頁空間也進行地址對映,建立上一級頁表,用於儲存頁表的對映關係。這裡對頁表的10個頁面進行對映只需要10個頁表項,所以上一級頁表只需要1頁就足夠(可以儲存2^10=1024個頁表項)。在程序執行時,只需要將這1頁的上一級頁表調入記憶體即可,程序的頁表和程序本身的頁面,可以在後面的執行中再i周入記憶體。

如圖3-11所示,這是Intel處理器80x86系列的硬體分頁的地址轉換過程。在32位系統中,全部32位邏輯地址空間可以分為2^20(4GB/4KB)個頁面。這些頁面可以再進一步建立頂級頁表,需要2^10個頂級頁表項進行索引,這正好是一頁的大小,所以建立二級頁表即可。


圖3-11  硬體分頁地址轉換
舉例,32位系統中程序分頁的工作過程:假定核心已經給一個正在執行的程序分配的邏輯地址空間是0x20000000到0x2003FFFF,這個空間由64個頁面組成。在程序執行時,我們不需要知道全部這些頁的頁框的實體地址,很可能其中很多頁還不在主存中。這裡我們只注意在程序執行到某一頁時,硬體是如何計算得到這一頁的頁框的實體地址即可。現在程序需要讀邏輯地址0x20021406中的位元組內容,這個邏輯地址按如下進行處理:
    邏輯地址: 0x20021406 (0010 0000 0000 0010 0001 0100 0000 0110 B)
    頂級頁表字段:0x80 (00 1000 0000 B)
    二級頁表字段:0x21 (00 0010 0001B)
    頁內偏移量欄位:0x406  (0100 0000 0110 B)

頂級頁表字段的0x80用於選擇頂級頁表的第0x80表項,此表項指向和該程序的頁相關的二級頁表;二級頁表字段0x21用於選擇二級頁表的第0x21表項,此表項指向包含所需頁的頁框;最後的頁內偏移量欄位0x406用於在目標頁框中讀取偏移量為0x406中的位元組。

這是32位系統下比較實際的一個例子。看似較為複雜的例子,有助於比較深入地理解,希望讀者能自己動手計算一遍轉換過程。

建立多級頁表的目的在於建立索引,這樣不用浪費主存空間去儲存無用的頁表項,也不用盲目地順序式查詢頁表項,而建立索引的要求是最高一級頁表項不超過一頁的大小。在 64位作業系統中,頁表的劃分則需要重新考慮,這是很多教材和輔導書中的常見題目,但是很多都給出了錯誤的分析,需要注意。

我們假設仍然釆用4KB頁面大小。偏移量欄位12位,假設頁表項大小為8B。這樣,其上一級分頁時,每個頁框只能儲存29(4KB/8B)個頁表項,而不再是210個,所以上一級頁表字段為9位。後面同理繼續分頁。64=12+9+9+9+9+9+7,所以需6級分頁才能實現索引。很多書中仍然按4B頁表項分析,雖然同樣得出6級分頁的結果,但顯然是錯誤的。這裡給出兩個實際的64位作業系統的分頁級別(注意:裡面沒有使用全部64位定址,不過由於地址位元組對齊的設計考慮,仍然使用8B大小的頁表項),理解了表3-2中的分級方式,相信對多級分頁就非常清楚了。

表3-2 兩種系統的分級方式
平臺 頁面大小 定址位數 分頁級數 具體分級
Alpha 8KB 43 3 13+10+10+10
X86_64 4 KB 48 4 12+9+9+9+9

基本分段儲存管理方式

分頁管理方式是從計算機的角度考慮設計的,以提高記憶體的利用率,提升計算機的效能, 且分頁通過硬體機制實現,對使用者完全透明;而分段管理方式的提出則是考慮了使用者和程式設計師,以滿足方便程式設計、資訊保護和共享、動態增長及動態連結等多方面的需要。

1) 分段。

段式管理方式按照使用者程序中的自然段劃分邏輯空間。例如,使用者程序由主程式、兩個子程式、棧和一段資料組成,於是可以把這個使用者程序劃分為5個段,每段從0 開始編址,並分配一段連續的地址空間(段內要求連續,段間不要求連續,因此整個作業的地址空間是二維的)。其邏輯地址由段號S與段內偏移量W兩部分組成。

在圖3-12中,段號為16位,段內偏移量為16位,則一個作業最多可有2^16=65536個段,最大段長為64KB。


圖3-12  分段系統中的邏輯地址結構
在頁式系統中,邏輯地址的頁號和頁內偏移量對使用者是透明的,但在段式系統中,段號和段內偏移量必須由使用者顯示提供,在髙級程式設計語言中,這個工作由編譯程式完成。

2) 段表。

每個程序都有一張邏輯空間與記憶體空間對映的段表,其中每一個段表項對應程序的一個段,段表項記錄該段在記憶體中的起始地址和段的長度。段表的內容如圖3-13所示。


圖3-13  段表項
在配置了段表後,執行中的程序可通過查詢段表,找到每個段所對應的記憶體區。可見,段表用於實現從邏輯段到實體記憶體區的對映,如圖3-14所示。


圖3-14  利用段表實現地址對映

3) 地址變換機構。

分段系統的地址變換過程如圖3-15所示。為了實現程序從邏輯地址到實體地址的變換功能,在系統中設定了段表暫存器,用於存放段表始址F和段表長度M。其從邏輯地址A到實體地址E之間的地址變換過程如下:
  • 從邏輯地址A中取出前幾位為段號S,後幾位為段內偏移量W。
  • 比較段號S和段表長度M,若S多M,則產生越界中斷,否則繼續執行。
  • 段表中段號S對應的段表項地址 = 段表起始地址F + 段號S * 段表項長度,取出該段表項的前幾位得到段長C。若段內偏移量>=C,則產生越界中斷,否則繼續執行。
  • 取出段表項中該段的起始地址b,計算 E = b + W,用得到的實體地址E去訪問記憶體。

圖3-15  分段系統的地址變換過程

4) 段的共享與保護。

在分段系統中,段的共享是通過兩個作業的段表中相應表項指向被共享的段的同一個物理副本來實現的。當一個作業正從共享段中讀取資料時,必須防止另一個作業修改此共享段中的資料。不能修改的程式碼稱為純程式碼或可重入程式碼(它不屬於臨界資源),這樣的程式碼和不能修改的資料是可以共享的,而可修改的程式碼和資料則不能共享。

與分頁管理類似,分段管理的保護方法主要有兩種:一種是存取控制保護,另一種是地址越界保護。地址越界保護是利用段表暫存器中的段表長度與邏輯地址中的段號比較,若段號大於段表長度則產生越界中斷;再利用段表項中的段長和邏輯地址中的段內位移進行比較,若段內位移大於段長,也會產生越界中斷。

段頁式管理方式

頁式儲存管理能有效地提高記憶體利用率,而分段儲存管理能反映程式的邏輯結構並有利於段的共享。如果將這兩種儲存管理方法結合起來,就形成了段頁式儲存管理方式。

在段頁式系統中,作業的地址空間首先被分成若干個邏輯段,每段都有自己的段號,然後再將每一段分成若干個大小固定的頁。對記憶體空間的管理仍然和分頁儲存管理一樣,將其分成若干個和頁面大小相同的儲存塊,對記憶體的分配以儲存塊為單位,如圖3-16所示。


圖3-16  段頁式管理方式
在段頁式系統中,作業的邏輯地址分為三部分:段號、頁號和頁內偏移量,如圖3-17 所示。


圖3-17  段頁式系統的邏輯地址結構
為了實現地址變換,系統為每個程序建立一張段表,而每個分段有一張頁表。段表表項中至少包括段號、頁表長度和頁表起始地址,頁表表項中至少包括頁號和塊號。此外,系統中還應有一個段表暫存器,指出作業的段表起始地址和段表長度。

注意:在一個程序中,段表只有一個,而頁表可能有多個。

在進行地址變換時,首先通過段表查到頁表起始地址,然後通過頁表找到頁幀號,最後形成實體地址。如圖3-18所示,進行一次訪問實際需要三次訪問主存,這裡同樣可以使用快表以加快查詢速度,其關鍵字由段號、頁號組成,值是對應的頁幀號和保護碼。


圖3-18  段頁式系統的地址變換機構