作業系統之儲存器管理方式
儲存器管理
儲存器的層次結構
儲存器設計為層次結構的原因
雖然儲存器的容量不斷擴大,但是隨著軟體在功能、規模、種類上的急劇增加,儲存器仍然是一種比較稀缺的資源;對它的管理常常影響到儲存器的利用效率,而且對系統性能也有一定的影響。一般的,對儲存器有以下三條期望:
- 容量越大越好;
- 訪問越快越好;
- 價格越低越好;
- 以上都能同時實現(不屬於可期望範圍之內)
常見儲存器層次劃分
對儲存器的三條期望無法同時滿足,所以需要在三者之間實現一種平衡,其目的還是提高系統性能(吞吐量和資源利用率);實現這一目的的方法就是設定快取。層次結構中,低一層為高一層的快取:低一層的儲存介質通常容量更大、價格更低但是訪問速度更慢(相比上一層而言),所以高一層+低一層=容量較大+訪問較快+價格適中;常見的層次結構劃分如下:
- 暫存器
- 快取記憶體
- 主儲存器
- 磁碟快取
- 固定磁碟
- 可移動儲存介質
其中,CPU暫存器和主存(前4級)也被稱為可執行儲存器;主要是系統對放置其中的資訊的訪問方式和賦存中資訊的訪問方式不同:程序通過一條load或者store指令可以實現對可執行儲存器的訪問,但是對輔存的訪問通常涉及中斷、裝置驅動程式以及物理裝置的執行,所以消耗的時間遠遠高於訪問可執行儲存器的時間;
程式的裝入和連結
程式要在系統中執行,必須先將其裝入記憶體,然後將其作為程序的一部分從而得以執行;程式的執行通常需要經過一下幾個步驟(嗯,是通常):
- 編譯:由編譯程式對使用者源程式進行編譯,生成若干個目標模組;
- 連結:由連結程式將編譯後生成的目標模組以及它們所需要的庫檔案連結在一起,形成一個完整的裝入模組;
- 裝入:由裝入程式將裝入模組裝入記憶體;
這裡需要注意的是,雖然這裡指明瞭有三步,但是並沒有說明這三步是什麼時候執行;不同的執行時機反映不同的儲存器管理策略;
程式的裝入
再將一個裝入模組裝入記憶體時,通常有三種方式:
絕對裝入方式
該裝入方式中,程式的相對地址(邏輯地址)和實際記憶體中的地址(實際地址)是相同的,即程式中使用絕對地址,由於程式在編譯或者彙編時給出邏輯地址,故該方法對程式設計師要求較高,而且一旦程式修改,可能所有的地址都需要修改。該裝入方式適合系統較小,且僅能執行單道程式時使用;
可重定位裝入方式(也稱為靜態重定位)
裝入模組中使用相對地址。相對地址一般從0開始;採用可重定位裝入方式裝入模組後,會使裝入模組中的所有邏輯地址與實際裝入記憶體後的實體地址不同,所以需要有一個將邏輯地址轉變為實體地址的過程,通常將該過程稱為重定位;又因為地址變換通常是在程序裝入時一次性完成,以後不再改變,故稱為靜態重定位方法;
該方法可用於多道程式環境下;
動態執行時裝入
可重定位裝入方式由於地址轉換是在程序裝入時一次性完成,以後地址不再改變,所以不允許程式和資料在記憶體中移動,這不利於提高儲存器的利用效率。改變方法就是將地址轉換推遲到指令執行時再進行,這樣就允許程式和資料在記憶體中移動,便於系統對儲存器的管理,為了使地址轉換不影響指令的執行速度,這種方式需要一個重定位暫存器的支援。
程式的連結
在對目標模組進行連結時,根據進行連結的時間不同,可以分為三種連結方式:
靜態連結
在程式執行之前,現將各個目標模組及它們所需要的庫函式連結成一個完整的模組,以後不再拆開;這種事先連結的方式稱為靜態連結;進行靜態連結時需要解決的問題有:相對地址的轉換和變換外部呼叫符號;
裝入時動態連結
在程式裝入記憶體時,採取邊裝入邊連結的方式,即在裝入一個目標模組時,如果發生一個外部呼叫事件,將引起裝入程式去找出相應的外部目標模組,將其裝入記憶體。其優點:
- 便於修改和更新程式。對某一模組的修改只會引起該模組的重新編譯和內部連結;
- 便於實現對目標模組的共享。採用動態連結方式時,OS可以將一個目標模組連結到幾個應用模組上,從而實現對該模組的共享;而靜態連結時,每個應用模組都將擁有共享模組的一份拷貝,浪費記憶體空間;
執行時動態連結
不需要將所有可能用到的模組都一次性裝入記憶體即執行程式,當程式需要的模組不在記憶體時,OS將尋找該模組,將其裝入記憶體。這樣,凡是未用到的模組都將不用裝入記憶體,提高了記憶體空間的利用率;即將連線過程推遲到程式執行時進行;
連續分配儲存管
單一連續分配
單道程式環境下,儲存區被分為系統區和使用者區兩部分,通常系統區位於低地址部分,供OS使用;使用者區僅裝有一道使用者程式,整個使用者區由該程式獨佔,這種方法稱為單一連續分配;
固定分割槽分配
多道程式環境下,將記憶體的使用者空間劃分為若干個固定大小的分割槽,然後為使用者程式分配;在劃分上,可以劃分為相同大小的若干塊,也可以劃分為不同大小的若干塊;一般來說相同大小的劃分常用於專用系統(提前得知每個程式所需要的記憶體大小相差不大),不同大小的劃分更為常見;一般劃分為多個較小的分割槽、適量的中等分割槽、少量的大分割槽;
通常將分割槽塊按大小將其排隊,並建立分割槽使用表,每一個表項包括分割槽塊的記憶體起始地址、狀態、大小、分割槽號等資訊;
動態分割槽分配
動態分割槽分配又稱為可變分割槽分配,它根據程序的實際需要為之分配記憶體空間,在實現動態分割槽分配時需要解決以下三個問題:使用的資料結構、分割槽分配方法、分割槽的分配和回收操作。
使用的資料結構
用以描述空閒分割槽,常見的有:
空閒分割槽表:每一個表項記錄分割槽號、分割槽大小、 分割槽的起始地址;
空閒分割槽鏈:每一個空閒分割槽起始部分設定一些用於控制分割槽分配的資訊以及用於連結各分割槽所用的前向指標,在分割槽尾部則設定一個後向指標,通過前後向指標,將所有空閒分割槽連結成一個雙向連結串列;
分割槽分配演算法
常見的有四種順序式搜尋演算法和三種索引式演算法
- 順序式搜尋演算法
- 首次適應演算法(First Fit)
- 迴圈首次適應演算法(Next Fit)
- 最佳適應演算法(Best Fit)
- 最壞適應演算法(Worst Fit)
- 索引式演算法
- 快速適應演算法(Quick Fit)
- 夥伴系統(Buddy System)
- 雜湊演算法
- 順序式搜尋演算法
分割槽的分配和回收操作
分割槽分配操作中涉及兩個操作:分割槽的查詢和切割;所謂查詢就是指尋找一個大小合適的空閒分割槽塊;切割就是指在找到這樣的空閒分割槽塊之後,按照切割條件判斷是否允許將這一空閒分割槽塊的空間分配給請求程序;
分割槽回收操作主要涉及的問題就是空閒塊之間的合併,不同的佈局環境有著不同的操作:
- 回收區X同上一塊空閒區A相鄰:合併A和X並修改A的大小;
- 回收區X同下一塊空閒區B相鄰:合併A和B並修改X的大小;
- 回收區X同時和A、B相鄰:合併A、X、B並修改A的大小;
- 回收區X和空閒塊不相鄰:新建一個空閒表項,填充相關資訊後將其首地址插入到空閒鏈的適當位置;
動態可重入分割槽分配
連續分配方式的一個重要特點就是,一個系統或者使用者程式必須裝入一塊連續的記憶體空間,當一臺計算機連續執行一段時間後,其記憶體空間將產生不少小的分割槽,而缺乏大的空閒分割槽;這樣即便這些分散的小空間的總量大於要裝入程式的需求,但是由於他們不相鄰,所以也就無法裝入該程式;這些小的分割槽就是“碎片”。若要利用這些“碎片”,可採用的一種方式就是將記憶體中的所有作業進行移動以實現將小碎片整合在一塊的目的,這一過程稱為“緊湊”;但是,每經過一次移動後,程式在記憶體中的位置就發生了變化,需要對程式的地址加以修改,但是這相當麻煩,而且大大地影響到系統的效率;所以,希望通過一種方法,只移動程式在記憶體中的位置,但是並不需要對相對地址進行修改;動態重定位就是這樣的一種方法;其實,動態重定位和程式的動態執行時裝入有著相似的原理:將地址轉換延遲到指令執行時再進行:
為使地址的轉換不影響到系統指令的執行速度,必須有硬體地址變換機構的支援,即在系統中增設一個重定位暫存器,用它來記錄資料在記憶體中的起始地址。程式中的指令期地址是有相對地址與重定位暫存器中的地址相加得到的,當系統進行了“緊湊”之後,只需要修改暫存器中的內容,而不需要對所有的地址進行變換。
分頁儲存管理方式
頁的引入及其組織形式
分頁管理系統將程序的邏輯地址空間劃分為若干個頁,對頁進行編號;同樣的將實體記憶體空間也劃分為若干塊並編號。在為程序分配記憶體空間時,以塊為單位,將程序中的若干頁裝入可以不相鄰的若干物理塊中。由於程序的最後一頁經常裝不滿,從而形成了頁內碎片;
頁面大小:頁面大小如果選的過於小,那麼系統就會有很多頁,會增加系統管理上的難度——維護頁表、對頁面進行換出換入都比較耗效能;頁面大小如果選擇的過於大,那麼系統就會產生較多的業內碎片,不利用提高儲存器的利用率;通常大小選擇為1kb-8kb;
分頁地址中,地址由兩部分內容組成,第一部分是頁號,第二部分是頁內偏移,即頁內地址;其中偏移量佔12為,頁號佔20位;
頁表
分頁系統中,允許程式離散分佈在記憶體中的物理塊中,為了管理這些頁面,系統將維護一個頁表,從而建立頁面到物理塊的關聯;常在頁表結構裡設定對頁面內容的訪問控制,
地址變換機制及快表
為了將使用者地址空間裡的邏輯地址轉換為記憶體空間中的實體地址,需要一個地址變換機制將分頁地址變換為實體地址;由於該轉換執行頻率很高,所以頁表功能常常使用一組暫存器來實現,即將頁表存放在暫存器中,但是隨著程式複雜度的提高,頁表長度也變得很大,所以就將頁表存放在記憶體中而在暫存器裡存放頁表首地址和頁表長度;
當程序需要訪問某個邏輯地址中的程序時,地址變換機制將識別頁表地址中的頁號和頁內偏移部分,然後以頁號索引檢索頁表,不過在此之前應有範圍檢查,以判斷是否發生越界錯誤;如果沒有錯誤,那麼使用頁表始地址與頁號和頁表項的乘積相加,得到頁表項在頁表中的地址,從而讀出實體地址,將之裝入實體地址暫存器中,之後配合使用頁表地址中的頁內偏移部分,即可完成地址轉換;
從上面的轉變過程來看,CPU訪問一個實體地址,需要兩次訪問記憶體:一次是查詢頁表,得到實體地址,另一次是真正訪問地址中的內容,這樣效率就降低了近一半;以這樣的代價換取儲存空間的利用率提升是不值得,為了提高地址轉換效率,一種合理方法便是:快取,基於區域性性原理的快取機制,即快表;
快表是地址轉換結構中的一種具有並行查詢能力的特殊高速緩衝暫存器,又稱為聯想暫存器;當CPU給出有效地址後,地址轉換結構就將頁號送入高速緩衝暫存器,進行一次查詢,如果有相匹配的頁號,表示要訪問的頁表資料在快表裡,可直接在快表裡獲得對應的物理塊號。如果沒有找到,則需要再次訪問記憶體中的頁表以獲得物理塊地址,找到該地址後就將其放入快表的一個暫存器單元裡,即修改快表。如果快表已滿,則需要找到一個寄存單元執行換出。
據統計,從快表中找到所需表項的概率高達90%以上,這樣由於增加了地址變換機構而造成的速度損失可以減小到10%以下,達到可以接受的程度。
兩級頁表和多級頁表
由於現代計算機系統支援非常大的邏輯空間,導致在系統中難以找到一塊連續的記憶體空間存放頁表;關於這個問題,有兩種解決方案:一是使用離散的方式儲存頁表;二是將需要的頁表存放在記憶體中,不需要的存放在外存中;
兩級頁表:
將頁表進行分頁離散儲存之後,就需要為頁表再建立一張索引表(頁表為實體記憶體塊的檢索表),這張表即為外層頁表。該表項結構分為三部分:外層頁號+外層頁內地址+頁內地址;其地址轉換過程如下:首先根據外層頁號m得到頁面所在首地址p(p=m*外層頁表項+外層頁表首地址),由此地址p和外層頁內地址x得到頁面所在物理塊的首地址n,由n和頁內地址一起得到最終指令的實體地址;這樣,獲得一條指令的內容就需要三次訪問記憶體了。一次是訪問外表,得到頁面所在物理塊的首地址;第二次是根據頁面首地址和外層頁內地址得到實際指令的首地址;第三次就是訪問實際資料了。
多級頁表和兩級頁表類似,理解多級頁表的概念,可類比多重陣列;
反置頁表
頁表是為所用頁面而設計的,頁表項中儲存的是頁面對應的實體地址;反置頁表則是為記憶體中的物理塊編號,使用頁表來管理物理塊,其中頁表項中儲存的是頁面以及程序的標記,表示該物理塊所屬於哪個程序,儲存的是那個頁面的資料;有些系統使用反置頁表來管理記憶體;但是還有一個問題就是,反置頁表只能建立已調入記憶體中的頁面和物理塊之間的關聯,但是一個程序的所有頁面不一定全部會調入記憶體,這裡就涉及頁面是否調入記憶體的管理。
一般來說,使用Hash表來管理反置頁表來提高檢索速度,但是使用Hash表則需要解決地址衝突的問題,該問題有很多種解決方法,這裡不做敘述;
分段儲存管理方式
從單一連續分配方法發展到固定分割槽分配再到動態分割槽分配,再到分頁儲存管理,推動這一系列改進的動力是提高儲存空間的利用率,而引入分段儲存管理方式的目的在於便於程式設計、資訊共享、資訊保護、動態增長和動態連結的實現:
- 分頁系統中,頁面內的程式碼是空間地址上的關係而不是邏輯內聚的,程式設計時希望引入的是一塊邏輯相關的程式碼;
- 由於分頁系統中頁中的內容不代表邏輯模組,所以不便基於分頁管理實現邏輯程式碼共享;
- 由於具有邏輯體系的程式碼段可能分佈再多個頁面,這樣對這些程式碼段的保護就難以進行;
- 頁面往往具有固定的大小,但是程式中很容易出現數據大小未知的情況,這樣使用頁面管理就不方便;
- 執行時動態連結的實現,需要以模組為單位進行連結,即目標程式應該作為連結的基本單位,所以分頁系統對此的支援也不是很好;
上面提到的5個方面,使用分段儲存都可以得到滿意的解決;
分段概念及其記憶體組織形式
在分段儲存管理方式中,記憶體空間被劃分為若干個段,每個段定義了一組邏輯資訊,每個段使用連續的記憶體空間,各個段的長度由對應的邏輯資訊組的長度決定,因此段的長度往往不等;由於作業的地址空間被劃分為若干段,所以地址空間具有二維性,而分頁系統中,地址空間的分配具有一維性;
分段儲存管理中,地址空間仍然有兩部分組成,一部分為段號,另一部分為段內地址;同樣,為了管理這些段,記憶體中設有段表。其中段表項記錄每個段的始地址和該段的長度;
地址轉換機制
地址轉換方式基本同分頁系統:首先從指令內容中得到短號,並由此定位到段表項;由段表項的內容獲得該段的實體地址,之後由段內地址配合計算得出指令或者資料的實體地址;
分段、分段系統中的資訊共享
雖然分頁系統中也可以實現對資訊的共享,但是,如果共享的資訊過於龐大,那麼對應的頁的數目就會很多,這樣在每個共享該資料的程序控制塊裡儲存這些共享的頁面就會使用不少的空間,使得PCB的體積過於龐大;但是使用分段系統的話,由於邏輯相關的程式碼被儲存在一個段裡,所以只需要儲存一個段地址以及段長度即可,換言之,分段系統中儲存的是共享資訊塊的數量,而分頁系統則儲存的是共性資訊塊的體積