1. 程式人生 > >作業系統總結之虛存

作業系統總結之虛存

虛擬記憶體
前一章記憶體管理介紹了幾種技術如分頁分段把一個程序分成多個頁,分開存放,在PCB中維持一個頁表。程序執行的前提是程序的全部頁都已經在記憶體中了。
虛擬記憶體技術就解決了這個問題,不需要一個程序把全部的頁都放在記憶體才能執行。
動態載入雖然也解決了這個問題,但是需要程式設計師完成,非常麻煩。
其實我們發現,一個程式包含了很多條件語句還有異常處理等,這些程式碼肯定要選擇執行的。所以全部調入會顯得冗餘,增加了磁碟到記憶體的傳輸時間。並且減少一個程序的空間可以使得記憶體容納更多的程序,增加

多道程式的度。
虛擬地址空間就是一個邏輯檢視,通過MMU對映到實體地址空間。
稀地址空間:程序的堆和棧之間的空白的虛擬地址空間。
程序虛擬地址空間內容:堆向上伸展,棧向下伸展,程式碼和資料。中間放共享庫。
虛擬記憶體可以通過共享頁將檔案或記憶體共享給多個程序。每個程序都認為庫位於自己的虛擬地址空間。
按需調頁:一個程序分成多個頁,在需要時調入相應的頁,也稱為懶惰交換。
按需調頁對於效能的影響很大,因為會發生頁錯誤,所以儘量減少頁錯誤。
交換是將整個程序看成一個整體,通過交換程式進行交換,而懶惰交換是將一個程序看成多個頁,通過調頁程式進行交換。   /*pager VS swapper*/
而我們通過有一張頁表維護有效-無效位來區分哪些頁在記憶體,哪些頁在磁碟。如果在記憶體且頁號有效,則記為v,如果在磁碟上,則為i。
如果訪問無效位的頁,則通過頁錯誤方式來解決即如果發現要訪問的頁不在記憶體,則:
1.終止程序,儲存現場,並通知作業系統。
2.尋找空閒幀,如果沒找到,用到頁面置換技術。
3.將磁碟上的頁排程到相應幀中。
4.重新開始指令。
純粹按需調頁:不斷頁錯誤,不斷將頁調入記憶體。
頁錯誤發生也是有不同代價的,如果在取指時就發生,則只需要重新取指,如果在獲得運算元時發生,則需要重新取指,譯碼,取運算元,代價就大了很多。
但是如果ADD A,B,A  A+B->A,當寫入A時出錯,重新執行這條指令,但是A已經被改變了,所以結果會不對。解決方案是用臨時的暫存器儲存原來的值。

有效訪問時間:(1-p)*記憶體訪問時間+p*頁錯誤時間。   /*考點*/
頁錯誤的具體過程:
1.告知作業系統。
2.儲存現場。
3.確定頁表的i代表頁錯誤,因為i可能代表頁不存在。
4.磁碟讀入空閒幀。
5.修改頁表和幀表。
6.恢復。
頁錯誤處理時間主要是:
1.處理頁錯誤。
2.讀入頁。
3.恢復。
磁碟專門有個交換空間,用於交換資料,處理速度要快。可以在交換空間執行按頁排程。
寫時複製:建立程序的開始可能不需要按需調頁,子程序共享父程序的資源和地址空間。當任何一個程序寫入時,就為另一個程序建立一個頁面副本。fork
分配空閒頁當作頁面副本也有技巧,可以通過空閒緩衝池,分配時採用按需填零即只在分配之時清零,清除以前內容。

增加多道程式的度數會有“過度分配”的情況,當頁錯誤發生,需要調入頁面,但是記憶體中沒有空閒幀,那麼必須頁置換。頁置換是將頁錯誤的時間加倍了,因為要換入和換出。
基本頁置換:
按需調頁中需要在記憶體中有一塊空閒幀來存放調入的頁,如果沒有空閒幀,就要發生頁置換。
頁置換過程:挑一個犧牲幀,並更新幀表和頁表。
可以用修改位或髒位降低開銷,當修改位被設定,則意味著這個頁從磁碟讀入後已被修改,那麼就需要寫回,如果修改位沒被修改,則不需寫回。
引用串用來評估一個頁置換演算法的效能:記憶體引用的頁號序列。如1,2,3 表示引用頁號1,2,3。
當不考慮記憶體幀的數量的情況下,只有頁的第一次引用發生頁錯誤,但是如果幀的數量限制,則會複雜的多。
1.FIFO頁置換:         
將記憶體的頁看成是一個FIFO佇列,替換的頁是最舊的頁即最先調入記憶體的頁,加入的頁放到佇列的尾部。這不是一個好辦法,因為最先進入的頁可能是一直要用到的頁,如果替換的是活動頁,則此頁會馬上又一次頁

錯誤,換回記憶體。
Belady 異常:頁錯誤數隨著記憶體幀數的增加而增加。
2.最優置換 OPT
不會產生Belady異常,並且頁錯誤率是最低的。因為他替換的是將來最久才被用到的頁。
3.LRU置換
選擇的頁是最近最少使用的頁。
對於引用串,如果倒轉,LRU置換和OPT置換的頁錯誤率是一樣的。
LRU實現需要硬體支援:
1.計數器。每個頁幀會附帶一個最近使用時間,置換出的頁就是時間最小的。
2.棧。棧頂加入頁,棧尾寫出頁。
4.近似LRU置換
因為LRU實現需要許多硬體支援,因此可能只能近似的實現LRU。
通過新增引用位,每當一個頁被引用,該為就置1.通過檢查該位,可以知道哪些頁未被使用。
(1)附加引用位演算法。
在一個頁的引用位保留8位,初始為0000 0000,第一次被使用,則1000 0000,第二次未被使用,則0100 0000.以此類推。找到這8位化為10進位制後最小的頁置換。
(2)二次機會演算法。
也是在頁中保留一個引用位,如果為1,則給予第二次機會,如果為0,則直接置換。
(3)增強型二次機會演算法。
將引用位和修改位作為有序對,(0,0)表示未被引用和修改,則說明是最佳的LRU置換頁。
5.基於計數的頁置換
(1)Least frequently used LFU:保留一個計數器,記錄引用次數。缺點是以前一直用,但是現在不用,則仍會留在記憶體。
解決方法:定期將計數右移一位。
(2)MFU:最常使用頁置換,即把計數最大的頁換出。
6.頁緩衝演算法
7.應用程式:不需要提供虛擬記憶體。
生磁碟:沒有檔案系統的磁碟。

接下來講幀分配,幀分配的最小數量是根據計算機體系結構,最大數量是根據實體記憶體數量。
分配方法:
1.平均分配。
2.比例分配。根據優先順序和程序大小。
幀分配和頁置換是相關聯的。
全域性置換:一個程序從任意幀中選擇一個置換,不管該幀是否已分配。 缺點是不能控制頁錯誤率。
區域性置換:僅從自己的分配幀中置換。

顛簸:頻繁調頁。
顛簸發生情景:
當CPU使用率降低時,CPU匯入更多程序,如果用全域性置換,如果一個程序需要很多幀,因此發生頁錯誤會從其他程序中拿一點,而如果其他程序也頁錯誤,則會從其他程序中拿幀,因此程序都到程序的等待調頁裝置

佇列,CPU使用率降低,惡性迴圈。
採用區域性置換也不能防止系統顛簸。因此我們必須要預先就分配足夠多的幀。因此引入了局部模型。
區域性模型是那些經常使用的幀,因此程序分配的幀一定要大於區域性模型的幀大小。
1.工作集合模型:working-set model 。基於區域性性。
工作集合視窗:預設△是最近用到的頁。對於△的取值很關鍵。
工作集合:在工作視窗中使用的頁的集合。
如果總的可用幀數量為W,程序i的工作集合為WSi,則W-WSi為其餘的可用幀,直到<0就不分配。
如果在記憶體中的程序的工作集合之和大於可用幀數量,則系統顛簸。
2.頁錯誤頻率PFF。
預先設定頁錯誤率的上下界。當頁錯誤率大於上界,則為程序分配更多的幀。這樣非常直接。
當對於一個新的區域性進行按需調頁時,頁錯誤率達到波峰。

如果呼叫open(),需要先找目錄,再找檔案,因此需要記憶體訪問+磁碟訪問。如果將檔案I/O作為記憶體的普通訪問,則稱為檔案的記憶體對映。
在記憶體中的檔案可以修改就不立即寫回。
前面講到記憶體對映檔案,下面是記憶體對映I/O,一組記憶體專門對映到裝置暫存器,讀取該塊地址如同讀取裝置暫存器。

核心記憶體的分配與使用者程序的分配記憶體不同,使用者程序都是按頁分配,但是核心分配需要從空閒記憶體池中獲取,而不是通過空閒幀連結串列中獲取。
1.Buddy系統。
通過對於連續物理頁進行二分,以至於能夠最小包容核心需求記憶體即可。如如果核心需求23KB空間,則最小得到的空間為32KB,因為要是2的冪。
優點:快速合併。
缺點:內部碎片。
2.slab分配。
slab是由一個或多個物理頁組成。
cache都有一個或多個slab。而一個核心資料結構都有一個cache。
cache儲存核心。核心需要空間就直接從cache中獲得。
slab三種狀態:滿,空,部分滿。
slab先從部分滿的slab中分配,再從空的slab中分配。否則,分配新的slab,並賦給Cache。
slab沒有內部碎片而且能夠快速分配。因為已經Cache中建立好了空間。