1. 程式人生 > 實用技巧 >作業系統-Operating-System第三章02:地址空間和地址生成

作業系統-Operating-System第三章02:地址空間和地址生成

B站資源:作業系統_清華大學(向勇、陳渝)

Github資源:chyyuu/os_course_info

參考書籍:Operating systems: internals and design principles

Operating System Concepts

MIT公開課:6.828: Operating System Engineering

其他部落格內容[知識點]實體地址(空間)與虛擬地址(空間)1.1 虛擬地址和實體地址作業系統學習筆記(六):地址空間和地址生成

地址空間

以陣列為例,在陣列中每個元素佔一個位元組,則可以將這個陣列的長度類比於地址空間。

實體地址空間

硬體支援的地址空間

因為CPU是32位的,其匯流排地址是32位的,所以其地址匯流排可編碼的個數是 2 32 2^{32} 232(4G),這 2 32 2^{32} 232個實體地址的集合就是實體地址空間。

起始地址為0,直到 M A X s y s MAX_{sys} MAXsys

邏輯地址空間

在CPU執行的程序中看到的地址

起始地址為0,直到 M A X p r o g MAX_{prog} MAXprog

在早期的計算機中,程式是直接執行到實體記憶體(可以理解為記憶體條上的記憶體)上的。也就是說,程式執行的時候直接訪問的就是實體地址。如果,我們的一個計算機只執行一個程式,那麼只有這個程式所需要的記憶體空間不超過實體記憶體空間的大小,就不會有問題。但是,我們正在希望的是在某個時候同時執行多個程式。那麼這個時候,就會有個一個問題,計算機如何把有限的實體記憶體分配給多個程式使用呢?

某臺計算機總的記憶體大小是128M,現在同時執行兩個程式A和B,A需佔用記憶體10M,B需佔用記憶體110。計算機在給程式分配記憶體時會採取這樣的方法:先將記憶體中的前10M分配給程式A,接著再從記憶體中剩餘的118M中劃分出110M分配給程式B。這種分配方法可以保證程式A和程式B都能執行,但是這種簡單的記憶體分配策略問題很多。

問題1:程序地址空間不隔離。由於程式都是直接訪問實體記憶體,所以惡意程式可以隨意修改別的程序的記憶體資料,以達到破壞的目的。有些非惡意的,但是有bug的程式也可能不小心修改了其它程式的記憶體資料,就會導致其它程式的執行出現異常。這種情況對使用者來說是無法容忍的,因為使用者希望使用計算機的時候,其中一個任務失敗了,至少不能影響其它的任務。

問題2:記憶體使用效率低。在A和B都執行的情況下,如果使用者又運行了程式C,而程式C需要20M大小的記憶體才能執行,而此時系統只剩下8M的空間可供使用,所以此時系統必須在已執行的程式中選擇一個將該程式的資料暫時拷貝到硬碟上,釋放出部分空間來供程式C使用,然後再將程式C的資料全部裝入記憶體中執行。可以想象得到,在這個過程中,有大量的資料在裝入裝出,導致效率十分低下。

問題3:程式執行的地址不確定。當記憶體中的剩餘空間可以滿足程式C的要求後,作業系統會在剩餘空間中隨機分配一段連續的20M大小的空間給程式C使用,因為是隨機分配的,所以程式執行的地址是不確定的。但是我們的某些硬體是需要在固定的地址上去開始執行的,但是如果這個地址後邊被我們的程式佔有,那麼我們對這塊記憶體的修改,就可能導致某些硬體不可用了。

為了解決上述問題,人們想到了一種變通的方法,就是增加一箇中間層,利用一種間接的地址訪問方法訪問實體記憶體。按照這種方法,程式中訪問的記憶體地址不再是實際的實體記憶體地址,而是一個虛擬地址,然後由作業系統將這個虛擬地址對映到適當的實體記憶體地址上。這樣,只要作業系統處理好虛擬地址到實體記憶體地址的對映,就可以保證不同的程式最終訪問的記憶體地址位於不同的區域,彼此沒有重疊,就可以達到記憶體地址空間隔離的效果。

具體參考1.1 虛擬地址和實體地址

虛擬記憶體(Virtual memory)是一個允許程式從邏輯角度訪問記憶體的功能,而無需考慮物理可用的主記憶體量

一個程式通過虛擬地址中的頁碼數以及頁內偏移量來引用一個單詞。程序的每個頁碼都可以在主存中的任何地方,分頁系統提供了程式中使用的虛擬地址與主儲存器中的實際地址或者實體地址之間的動態對映。

利用可用的動態對映硬體,下一步的邏輯步驟是消除對程序的所有頁面同時駐留在主記憶體中的要求。 程序的所有頁面都保留在磁碟上。 執行某個程序時,其某些頁面位於主記憶體中。 如果引用的頁面不在主記憶體中,則記憶體管理硬體會檢測到該頁面並安排丟失的頁面要載入。

在這裡插入圖片描述

儲存由可直接定址(通過機器指令)的主儲存器和低速輔助儲存器組成,可通過將塊載入到主儲存器來間接訪問。 地址轉換硬體記憶體管理單元MMU)位於處理器和記憶體之間。 程式使用虛擬地址引用位置,虛擬地址被對映到實際的主記憶體地址中。 如果對不在真實儲存器中的虛擬地址進行引用,則將主存的一部分內容交換到輔助儲存器中,並交換所需的資料塊。在此活動期間,生成地址引用的過程必須暫停。 OS設計人員需要開發一種地址轉換機制,該機制幾乎不會產生任何開銷,並且需要一種儲存分配策略,以最大程度地減少記憶體級別之間的流量。

image-20201021190340892

地址生成

CPU

  1. ALU(Arithmetic&logical Unit)需要對邏輯地址中的內容進行讀寫操作;
  2. MMU(Memory Management Unit)將邏輯地址轉換成實體地址;
  3. CPU給匯流排傳送實體地址請求

記憶體

  1. 傳送實體地址的內容給CPU
  2. 或接收CPU資料到實體地址

作業系統

建立邏輯地址LA(Logic Address)和實體地址PA(Physical Address)的對映

邏輯地址生成

從最開始的指令碼foo()開始,首先進行編譯,得到機器可以識別的組合語言。之後進行編譯,將函式名從字串變為地址75;而這個函式可能是某個函式庫中的成員,而函式庫的位置程式是不知道的,這就需要連結,將需要的檔案拼接起來,此時可能在原先的程式碼前面插入了一段程式碼,比如地址偏移了100,此時函式地址變為了175;最後需要進行程式載入即重定位,因為這段程式不一定是從邏輯地址的0位開始的,比如是從1000開始的,那麼函式地址成為1175。經歷了這麼多步驟之後,生成的1175才是我們需要的邏輯地址。

邏輯地址生成的時間點

  1. 編譯時。假定起始地址已知,也就是我知道我的程式要放在哪,那麼編譯時就可以生成邏輯地址但是當起始地址改變時,比如修改了程式碼,必須重新編譯。老舊的功能機買來之後不允許下載軟體,這種情況下地址通常就是寫死的。
  2. 載入時。當你修改了程式碼或者安裝了各種新的軟體,寫程式時是無法知道新的程式碼儲存在什麼地址的。也就是編譯時起始位置未知時編譯器需生成可重定位的程式碼等到載入時重定位生成絕對地址。通常在可執行檔案的前面有一個重定位表,載入的時候改成絕對地址,程式就可以跑了。
  3. 執行時。執行到這條指令之前一直使用相對地址,當執行到這一條指令的時候,才可以去知道它確切訪問的地址。這種情況出現在使用虛擬儲存的系統裡。優點就是在程式執行過程中就可以將程式碼移動,而前面兩種生成時機都不可以。但是需要地址轉化硬體支援,相對較麻煩。

地址檢查

CPU執行到某條指令,得到它的邏輯地址,首先根據邏輯地址判斷所在它的偏移量是否在所在段(比如資料段)的長度之內,如果超出了段長度,認為是非法請求,否則認為是合法的。此時加上段基址得到實體地址,進行訪問。在這個過程中作業系統要做的就是設定段起始地址和最大邏輯地址空間(段長度)。

image-20201020203713293