作業系統原理之記憶體 一

2022-02-23 15:45:41 字數 3017 閱讀 2499

在彙編指令中,我們有時會看到如下指令:

.text

.entry:

**入口

call

40-

main:

.......

那麼這裡的40指向的是記憶體中的哪個位置呢?是記憶體的實際位址嗎?

顯然,如果是實際位址的話我們的程式必須被裝載在記憶體0位址處,但這樣做肯定是存在問題的,一方面,如果這樣的話每個程式都要放到0位址處;另一方面,記憶體0位址

處已經被作業系統占用。

因此,這裡的40必然是乙個邏輯位址(或相對位址)

那麼,程式在記憶體中需要修改源**中的邏輯位址,改為實際實體地址(如上圖程式被載入到記憶體1000處時40和300都被修改了),因為程式並不是始終存在於記憶體的同一位置的,在被換出(swap out)記憶體並再次換入(swap in)時很可能並不會被載入到同一位置,所以編譯時確定實際實體地址是不可取的;在這裡,更可行的方式是執行時動態加上乙個基位址(base)。

(如圖中所示,作業系統進行記憶體排程,將部分程式換出,將其他程式換入)

那麼這個基位址被存放在**呢?在linux中,基位址會被存到pcb中。在作業系統裡每個程序都有乙個資料結構與之對應,被稱為pcb(程序控制塊),當我們fork()乙個程序的時候實際上是建立了乙個pcb並從其父程序的pcb**繼承一些資料,並將這個資料結構插入到系統的程序樹中。

所以,整體大概是如下流程:

編譯程式->fork出pcb(程序)->在記憶體中找到空閒的記憶體空間->將這段空間的基位址賦值給pcb中的base欄位->引導程式->執行每行程式時將原始碼中的位址與pcb中的基位址相加。

當然為了提高效率當作業系統切換到當前程序時base欄位會被放入暫存器中,所以相加是在暫存器中進行,而且cpu本身為這種操作提供了硬體支援--mmu(記憶體管理單元)。

我們在平時玩遊戲或寫**時,認為我們所使用的程序(比如遊戲程式或eclipse)是整個存在於記憶體中的,而事實上呢?

如果您學過一些彙編或c/c++的話,可能會很自然地認為程序是如下組成的:

程序分為幾個段,每個段都有自己的特點,有不同的用途,而事實上就像上圖所示,我們前文所講的0位址並不是整個程式從0開始,而是程式中的每個段都從0開始,

程式的這幾個段有的唯讀(如**段),有的可寫(如資料段),如果同一處理的話明顯會造成混亂,比如錯誤地寫了程式段等。

因此程式在載入時並非整個一起載入進記憶體,通常是分段載入。

這種情況下,定位乙個位址就變為段的基位址+段內偏移量,如果使用之前那種載入整個程序的方式,pcb中只需要存放乙個程式基位址,而分段載入則需要

實際位址。

每個linux中的程序都會使用乙個程序段表(ldt表),而作業系統本身也是乙個程序,它也同樣使用的程序段表(gdt表)。

編譯程式-->建立pcb-->程式中的某個段(如**段)找到乙個空閒的記憶體空間-->將記憶體基位址存入pcb中的ldt表裡-->其它段載入過程類似

-->執行程式,將邏輯位址和ldt表中該段的基位址相加。

前文提到我們需要將首先我們的程式需要載入記憶體,在載入時需要在記憶體中找到空閒區域,因此必須將記憶體事先分割成不同區域,那麼如何分割記憶體才合理呢?

首先,我們可能會想到將記憶體等分為n個區域,但這明顯是不合理的,因為我們的程式占用空間大小不一,每個段需要的空間亦不相同。

一種很自然地想法是,根據每個段實際需要的大小進行分配,並記錄已經占用的空間和剩餘空間:

這樣,當乙個段請求記憶體時,就到空閒分割槽中申請一段記憶體,並在已分配分割槽表中記錄這一過程。

記憶體適配:

當乙個段請求記憶體時,如果有記憶體中有很多大小不一的空閒位置,那麼選擇哪個最合理?

1. 首先適配:空閒分割槽表中選擇第乙個位置(優點:查表速度快)

2. 最差適配:選擇乙個最大的空閒區域

3. 最佳適配:選擇乙個空閒位置大小和申請記憶體大小最接近的位置,比如申請乙個40k記憶體,而恰巧記憶體中有乙個50k的空閒位置(這裡最佳並不意味著最好,

因為最佳適配可能導致大量記憶體碎片)

儘管分割槽的方式解決了申請記憶體的問題,但很明顯的是其會帶來大量的記憶體碎片,意思是儘管我們記憶體中仍然存在很大空間,但全部都是一些零散的空間,當申請

大塊記憶體時會出現申請失敗。如圖中所示,灰色區域為記憶體碎片。

為了不使這些零散的空間浪費,作業系統會做記憶體緊縮,即將記憶體中的段移動到另一位置。但明顯移動程序是乙個低效的操作。

這就引入了記憶體分頁的機制:

如圖中所示,如果作業系統實現將記憶體分割成多個頁框,而段申請記憶體時按頁分配,這樣的話,乙個段最多浪費乙個頁框。也就不需要做耗時的記憶體緊縮操作了。

但如上圖所示,乙個段會被分割到多個頁框中,顯然,我們的記憶體重定位方式需要進一步改變。

待續。。。。

作業系統原理之記憶體 一

在彙編指令中,我們有時會看到如下指令 text entry 入口 call 40 main 那麼這裡的40指向的是記憶體中的哪個位置呢?是記憶體的實際位址嗎?顯然,如果是實際位址的話我們的程式必須被裝載在記憶體0位址處,但這樣做肯定是存在問題的,一方面,如果這樣的話每個程式都要放到0位址處 另一方面...

作業系統之記憶體管理

記憶體管理的功能有 1 空間分配與 2 位址轉換 3 空間擴充 4 儲存保護 將資料與程式裝入記憶體分以下步驟 1 編譯成模組 2 鏈結模組 分靜態 裝入時動態 執行時動態鏈結 3 將模組裝入記憶體 分絕對裝入 可重定位裝入 執行時動態裝入 邏輯位址與實體地址 訪問資料時是使用實體地址獲取資料,多個...

作業系統之記憶體管理

位址對映和重定位是乙個概念 適應於請求段的記憶體分配方法是最佳適應和可變分割槽 可重入 reentrant code 又稱為 純 purecode 是一種允許多個程序同時訪問的 為使各個程序所執行的 完全相同,絕對不允許可重入 在執行中有任何改變。目的 擴充主存容量 最基本的特徵 多次性 最主要的技...