《現代操做系統》精讀與思考筆記 第三章 內存管理

  本系列博文是《現代操做系統(英文第三版)》(Modern Operating Systems,簡稱MOS)的閱讀筆記,定位是正文精要部分的摘錄理解和課後習題精解,所以不會事無鉅細的全面摘抄,僅僅根據我的狀況進行記錄和推薦。因爲是英文版,部份內容會使用英文原文。html

  課後習題的選擇標準:儘可能避免單純的概念考察(如:What is spooling?)或者簡單的數值計算,而是可以引發思考加深理解的題目。爲了保證解答的正確性,每道題都會附上原書解答,而中文部分會適當加入本身的看法。原書答案下載地址(需註冊) 程序員

  注:本文部份內容須要讀者對頁式、段式、段頁式內存管理有基本瞭解。 算法

 

概念回顧

  交換技術(Swapping):內存緊縮、用於內存管理的位圖和鏈表、匹配算法:首次匹配、下次匹配、最佳匹配、最壞匹配;緩存

  虛擬內存:前身是手工完成的覆蓋技術(overlays);內存管理單元MMU及地址轉換:頁表、TLB(轉換檢測緩衝區,也稱爲關聯存儲器,俗稱快表)、多級頁表;app

  頁面調度算法less

  共享庫(shared libraries)/動態連接庫(DLL,Dynamic Link Libraries)dom

  段式內存管理、段頁式ide

 

1.TLB的譯名

  若是以前學習過國內的操做系統教材,TLB通常被稱爲快表,而不是轉換檢測緩衝區(Translation Lookaside Buffer)或關聯存儲器(associative memory)。對於國內常見的稱呼,容易知道它是作爲整個頁表的一個部分緩存,從而加快虛地址向實地址轉換的速度。所以,它和頁表的條目結構很相似。具體解釋見於P195~197,另外段式存儲管理中也可使用TLB加速訪問。對於不一樣地方出現的TLB,它緩衝的內容與其應用場景有關(MULTICS、Pentium等等)。能夠看出,這個譯名比較形象,不過原名更具體些。學習

 

2.倒排頁表(Inverted Page Tables)

  本科時學習「操做系統」的"基本分頁存儲管理方式"時,對於64位計算機、單個頁面4KB(即212B),兩級頁表已通過大而不能裝入內存。湯子瀛版《計算機操做系統》介紹了2種處理方式:使用三級或以上的頁表、將尋址空間下降到45位左右而不是64位。前者仍然比較繁瑣,後者可行性比較高。那時我就對前者心存疑惑:雖然可以將須要用的頁表調入內存,但是它們總大小仍然很大,有沒有更好的實現?接下來看一看《現代操做系統》提供的方式:倒排頁表。下面這部份內容取自原書P200~201的整理。this

  先簡述下問題所在:64位計算機中,若是頁面大小爲4KB,那麼64位尋址空間須要252個頁表項。假設每一個頁表項大小爲8B,那麼須要30PB的空間,在目前計算機發展階段顯然是不現實的。

  倒排頁表是一種解決方案,正如其名所揭示的:普通的頁表是將虛地址映射成物理地址,提供的是將頁號(page number)轉化爲頁框號(page frame number)的對應;這個轉化由MMU完成;而倒排頁表正相反,提供的是將頁框號轉化爲頁號的對應。頁框號是實際內存的大小/頁面大小,所以1GB內存只須要262,144個項便可,遠遠小於252這個數字。

  我的認爲,這個解決思路的妙處在於:32位下,頁表項總和比較少,至多兩級頁表也已夠用;而64位下,內存的大小(也即物理地址空間)與尋址空間(虛地址空間)相比反而顯得小了,這樣乾脆來個倒轉,不失爲一個很好的方法。

  固然這種解法雖然節約了大量的存儲空間,可是內存管理中須要的是將虛地址轉化成物理地址的機制,而不是正相反啊?這種映射是單向的,總不能每次轉化都把這個表遍歷一次吧?那樣作的開銷實在是太大了。

  一種解決方法是使用TLB,可是TLB也有失效(miss)的時候,這時仍是須要進行查找。一個可行的方法是將全部用到的虛地址hash掉,造成一個hash表來加速查找,一樣哈希值的虛地址造成一個鏈。若是hash表的槽數與物理內存的頁框數同樣多,那麼哈希表各表項平均長度爲1,這樣提升了查找速度。這個解決方法的演變能夠見下圖3-14。

  

 

3.LRU和NFU的算法實現

(1)LRU算法實現

  LRU,湯子瀛《計算機操做系統》譯爲「最近最久未使用」,也即在緩衝的全部頁面中,缺頁中斷髮生時,將最久未被使用的頁面置換出去。不過按照字面意思,Least Recently Used彷佛應是《現代操做系統》中譯版的「最近最少使用」,彷佛是須要統計頁面使用頻率的。這裏有必要先探討下這個翻譯問題。這個翻譯的區別在於,副詞least修飾的是recently仍是used。P206原文:

A good approximation to the optimal algorithm is based on the observation that pages that have been heavily used in the last few instructions will probably be heavily used again in the next few. Conversely, pages that have not been used for ages will probably remain unused for a long time. This idea suggests a realizable algorithm: when a page fault occurs, throw out the page that has been unused for the longest time. This strategy is called LRU (Least Recently Used) paging.

  這前半段和後半段意思並非很一致。按照前半段的意思,用的最多的(heavily used)最應該保留;然後半段,也即LRU的定義,反而是指「最久未使用」。假設這樣一種狀況,內存只能容納兩個頁,若是考察的時間跨度大於2,對於0,0,...,0,1的頁面訪問序列,此時訪問頁面2,前半段會認爲0的使用頻率最高,應該保留0,然後半段認爲0是最久未被使用的,應該保留1。這樣就產生了矛盾。不過既然是一個近似,按後半段更合適一些,這樣反而顯得「最近最久未使用」是一個更合適的譯法。《現代操做系統》提到的3種算法,其實都是符合定義的:

   一種實現是用一個特殊鏈表,將最近最多使用的放在表頭,最近最少使用的放在表尾,每次使用到的頁面若是在鏈表中,就把它取出並放到表頭。不過這個實現一方面很耗時,而且其實是「最近最久未使用」。

  一種硬件實現是使用一個計數器,每次執行指令自增1,每一個頁表項中提供一位來容納這個值,每次訪問時就把計數器的值存到訪問的頁表項中。淘汰頁面時選擇最小的便可。雖然很符合「最近最少使用」的含義,缺點是消耗了不少存儲空間;另外,計數器的溢出也是個問題。一樣是「最近最久未使用」。

  另外一種硬件實現則比較精巧。對於n個頁框的機器,提供一個n*n的矩陣,初始化爲全0。當訪問頁框k時,將這個矩陣第k行全設爲1,第k列全設爲0,此時(k,k)是0。在任意時刻,哪一行的二進制數最小,那麼它就是將被淘汰的頁面。能夠發現,這種作法中,最後被訪問的頁面會把它所在的行變爲最大的(k列全爲0,表明此列的大小影響不計;僅有k行全1,必然最大)。同時,頁面的使用頻率越高,那麼它就能「保持」的較大。即便上文中探討的做爲0,0,...0,1這種序列,仍然是保持1替換0,仍是「最近最久未使用」。原書對這個實現的圖3-17:

  

(2)NFU算法實現(原書P206~207)

  LRU的實現比較複雜,並且可能須要藉助特殊的硬件。一種軟件實現被稱爲NFU(Not Frequently Used,最不經常使用),每一個頁面使用一個計數器,每次時鐘中斷時,將頁面的R位(是否被引用,0或1)加到計數器上。缺頁中斷時置換計數器值最小的。

  這種實現的壞處是它「從不忘記任何事情」,簡單地說就是在以前計數器值比較高的頁面,即便再也不訪問,仍然會保持這個值;而別的頁面在後續始終沒法超過。對NFU作一個小修改,就能夠很好的模擬LRU:將R位增長前先計數器右移、R位增長到計數器左邊的最高位而不是右邊的最低位。修改後的算法稱爲老化(aging)算法。圖3-18是一個運行實例,其蘊含的特徵是:越高位越新,最近的使用權重最大;早期的使用記錄會隨着右移而捨棄。

  

  從中也可看出NFU與LRU的第一個區別:對於(e),LRU只能從3和5中二選一,3和5都在2個時鐘前訪問過,而NFU會明確地喚出3。另外一個區別是NFU只能追蹤有限次(相較於LRU的前兩種實現,要少一些),好比圖中的8次。前第9次和前1000次的訪問狀況是可有可無的。

 

4.頁的大小

  如何肯定頁的大小?之前我只知道應該綜合考慮,可是如何考慮?原書P219~220是一個很好的借鑑。

  假設頁面大小爲p字節,內存中共有n個段。

  首先考慮頁內碎片。平均來看頁內碎片佔了頁的1/2大小,那麼一共浪費了np/2的空間。

  頁面越小,進程運行時所需內存越小,只需把足夠的頁面裝載如內存便可;反之則越大。然而,頁面越小,須要的頁表項越多,頁表也越大。在頁傳輸這個數量級時,磁盤傳輸的時間主要花在尋道和旋轉延遲上,頁面大小不是關鍵因素,好比,裝入64個512B頁面須要64*10ms,而4個8KB可能只須要4*12ms。

  進程切換時,也表也須要從新裝載,頁面越小,裝入頁表越耗時。

  最後一點能夠用數學分析。若是進程大小平均s字節,頁面大小p字節,每一個頁表項須要e字節,那麼進程須要的頁數爲s/p,佔用了se/p的頁表空間, 頁內碎片在最後一頁浪費的是p/2,那麼因爲頁表和頁內碎片一共的所有開銷爲:

\[overhead = se/p + p /2\]

利用求導的方法,能夠解出最小化開銷overhead的p值:

\[p = \sqrt{2se}\]

  對於s = 1MB和頁表項爲8B,最優頁面大小是4KB。

 

5.有頁式、段式、段頁式,爲何沒有頁段式?

  這是我本科時學習操做系統的又一個疑惑。其實從技術角度來講,是能夠實現的;讀完《現代操做系統》有了新的體會:頁式更接近於硬件底層,對於程序員是透明的,你不多感覺到它的存在;而段這個概念就比較熟悉了,數據段、代碼段、段保護機制這些常常被提起。段是邏輯抽象,更貼近人的思考方式而不是計算機的運做方式。頁式、段式、段頁式都是在現實中經常使用的,並且《現代操做系統》的做者Andrew提到:Pentium的設計者面對相互衝突的目標:純頁式、純段式、段頁式管理,高效而簡潔的實現,至關值得稱讚("

All in all, one has to give credit to the Pentium designers. Given the conflict­ing goals of implementing pure paging, pure segmentation, and paged segments,
while at the same time being compatible with the 286, and doing all of this efficiently, the resulting design is surprisingly simple and clean",如何使用段頁式管理系統提供純段式和純頁式請參考原書3.7.3節)

  能夠看出,對於軟件設計,應該讓邏輯層在較高的位置,貼近硬件的機制在較低的位置——這就是段頁式的處理;而不是相反,也就沒有了使用所謂的頁段式的必要了。

 

課後習題選

16.The TLB on the VAX does not contain an R bit. Why?

譯:

  爲何VAX上的TLB沒有R位?

Answer:

  The R bit is never needed in the TLB. The mere presence of a page there means the page has been referenced; otherwise it would not be there. Thus the bit is completely redundant. When the entryis written back to memory, how-ever, the R bit in the memory page table is set.

分析:

  題目提到VAX這個機型實際上是誤導。通常頁表中都有R位(Referrence,最近是否訪問過)和M位(Modified,最近是否修改過),這兩位在一些調度算法中要用到;而TLB中必然保存的是最近引用過的頁,任何機型的TLB都沒有R位的必要。

 

21.Suppose that the virtual page reference stream contains repetitions of long sequences of page references followed occasionally by a random page reference. For example, the sequence: 0, 1, ... , 511,431, 0, 1, ... , 511, 332, 0, 1, ... consists of repetitions of the sequence 0, 1, ... , 511 followed by a random reference to pages 431 and 332. 

(a) Why won't the standard replacement algorithms (LRU, FIFO, Clock) be effective in handling this workload for a page allocation that is less than the sequence length?
(b) If this program were allocated 500 page frames, describe a page replacement ap­proach that would perform much better than the LRU, FIFO, or Clock algorithms.

譯:

  對於一個頁面訪問序列,會有一個長的重複序列0,1,...,511,末尾一個隨機數字,所以這個序列形如0, 1, ... , 511,431, 0, 1, ... , 511, 332, 0, 1, ... 。問題(a)爲何在負載小於重複序列的時候,標準的頁面置換算法(LRU、FIFO、Clock)對於這種序列很是低效?(b)若是這個程序只有500個頁框,請描述一種好的頁面置換算法。

Answer:

  (a) Every reference will page fault unless the number of page frames is 512,the length of the entire sequence.
  (b) If there are 500 frames, map pages 0–498 to fixed frames and vary only one frame.

 

分析:

  (a)就再也不贅述了,對於(b),實際上是徹底與提到的標準算法不同的,更接近於最優算法的實現,也即在可以預計將來的狀況下進行頁面管理。

 

35.A machine language instruction to load a 32-bit word into a register contains the 32-bit address of the word to be loaded. What is the maximum number of page faults this instruction can cause?

譯:

  一條機器指令,其功能是把一個32位字的數據裝入寄存器,指令自己包含了要裝入的字所在的32位地址。這個過程最多會引發幾回缺頁中斷?

分析:

  原文稍有點拗口,須要仔細分析。首先裝載指令時,若是它是跨頁的,會引發兩次缺頁中斷;其次,若是數據所在地址也跨頁了,又將引發兩次。若是數據必須對齊,那麼後者只有一次中斷;可是32位的指令未必要對齊,包括Pentium上也是這樣。

 

勘誤

1.P250習題19,"a 256-KB main memory"應爲256-MB,這個推論根據原書答案的計算過程而來。

相關文章
相關標籤/搜索