1. 程式人生 > >作業系統記憶體管理

作業系統記憶體管理

實體記憶體

Linux為了有效使用機器中的實體記憶體,在系統初始化階段記憶體被劃分成幾個功能區域:


其中,Linux核心程式佔據在實體記憶體的開始部分,接下來是供硬碟等塊裝置使用的高速緩衝區部分(其中要扣除顯示卡記憶體和ROM BIOS所佔用的記憶體地址範圍)

當一個程序需要讀取塊裝置中的資料時,系統會首先把資料讀到高速緩衝區中。當有資料需要寫到塊裝置上去時,系統也是先將資料放到高速緩衝區中,然後由塊裝置驅動程式寫到相應的裝置上。

記憶體的最後部分是可供所有程式隨時申請和使用的主記憶體區。核心在使用主記憶體區時,首先要向核心記憶體管理模組提出申請,並在申請成功後方能使用。

在Intel 80386及以後的CPU中提供了

兩種記憶體管理(地址變換)系統:記憶體分段系統分頁系統。其中分頁管理系統是可選擇的,由系統程式設計師通過程式設計來確定是否採用。Linux同時採用了分段和分頁機制。

記憶體地址空間概念

在Linux核心中,在進行地址對映操作時,我們要分清3種地址的概念:程序的虛擬(邏輯)地址、CPU的線性地址、實際的實體地址。

虛擬地址

虛擬地址是指由程式產生的段選擇子和段內偏移地址兩部分組成的地址。

(因為這兩部分組成的地址並沒有直接用來訪問實體記憶體,而是需要通過分段地址變換機制或對映後才對應到實體記憶體地址上,故被稱為虛擬地址。)

虛擬地址空間GDT對映的全域性地址空間和由LDT對映的區域性地址空間組成。

【關於GDT和LDT,請移步-<CPU的真實模式與保護模式>】

Intel 80x86 CPU可以索引16384個選擇符。若每個段的長度都取最大值4GB,則最大虛擬地址空間範圍是16384*4GB=64TB

CPU的記憶體管理給程式設計師提供了這樣一個抽象的記憶體模型:


程式設計師(無論是彙編的還是高階語言的)可以把記憶體分佈看做是如上圖所示,可以認為記憶體中只有自己的程式,自己獨佔CPU

這是硬體和作業系統一起提供給程式設計師的簡單抽象。

(底層的實現:地址變換、任務切換等對程式設計師是透明的)

邏輯地址是指由程式產生的與段相關的偏移地址部分。在Intel保護模式下即是指程式執行程式碼段限長內的偏移地址

應用程式設計師僅需與邏輯地址打交道,而分段和分頁機制對他來說完全透明的。(由載入器來設定分段)

Linux 0.12給每個程序都劃分了容量為64MB的虛擬記憶體空間。因此出現的邏輯地址範圍是0x0000000到0x4000000。(即設定一個LDT所管轄的範圍為64MB)

(現在的作業系統給程序劃定的虛擬記憶體是4GB,當然也可以更多。)

有些資料不區分邏輯地址和虛擬地址的概念,統稱邏輯地址。

線性地址

線性地址是虛擬地址到實體地址變換之間的中間層,是CPU可定址的記憶體空間中的地址

程式程式碼會產生邏輯地址(或者說是段中的偏移地址),加上相應段的基地址就生成了一個線性地址。(一個段最大有4G的虛擬地址空間,在載入器把程式載入時,很容易選擇一個空閒的段,填好GDT和LDT)

如果啟用了分頁機制,那麼線性地址可以再經變換產生一個實體地址。若沒有啟用分頁機制,那麼線性地址直接就是實體地址。

Intel 80386的線性地址空間容量為4GB。

實體地址

實體地址是指出現在CPU外部地址總線上的定址實體記憶體的地址訊號,是地址變換的最終結果地址。

記憶體分段機制

在真實模式下,定址一個記憶體地址主要是使用段基址和偏移值,段基址被存放在段暫存器中(如ds),並且段的長度被固定為64KB。段內偏移地址存放在任意一個可用於定址的暫存器中(如si)。


在保護模式下,段暫存器中存放的不再是被定址段的基地址,而是一個段描述符表中某一描述符項在表中的索引值。索引值指定的段描述符項中含有需要定址的記憶體段的基地址、段的長度值、段的訪問特權級等資訊。(這樣通過段描述符訪問段中的資訊,可檢查安全性,則就是所謂的保護模式)

這樣,在保護模式下定址一個記憶體地址就需要比真實模式下多一個環節,即需要使用段描述符表

注意,如果你不在一個段描述符中定義一個記憶體線性地址空間區域,那麼該地址區域就完全不能被定址,CPU將拒絕訪問該地址區域。


儲存描述符項的描述符表有3種類型,每種用於不同目的。

IDT中斷描述符表(Interrupt Descriptor Table),該表儲存了定義中斷或異常處理過程的段描述符。IDT表直接替代了8086系統中的中斷向量表。(使得在跳轉到中斷程式時也進行許可權檢查。)

GDT全域性描述符表(Globle Descriptor Table),該表可被所有程式用於引用訪問一個記憶體段。

LDT區域性描述符表(Local Descriptor Table),通常每個任務使用一個LDT表。每個LDT表為對應任務提供了更多的可用描述符項,因為也為每個任務提供了可定址記憶體空間的範圍

這些表可以儲存線上性地址空間的任何地方。為了讓CPU能定位GDT表、IDT表和當前的LDT表,需要為CPU分別設定GDTRIDTRLDTR三個特殊暫存器。


可以看出,每個任務的區域性描述符表LDT本身也是由GDT中描述符定義的一個記憶體段,在該段中存放著對應任務的程式碼段和資料段描述符,因此LDT段很短。同樣,每個任務的任務狀態段TSS也是由GDT中描述符定義的一個記憶體段。(TSS用於在任務切換時CPU自動儲存或恢復相關任務的當前執行上下文)

記憶體分頁管理

記憶體分頁管理機制的基本原理是將CPU整個線性地址記憶體區域劃分成4KB為1頁的記憶體頁面。程式申請使用記憶體時,系統就以記憶體頁為單位進行分配。

為了在80x86保護模式下使用分頁機制,需要把控制暫存器CR0的最高位置位


對於Intel 80386系統,其CPU可以提供多達4GB的線性地址空間。

作業系統的記憶體管理(以下為一家之言,僅供參考)

有兩套對記憶體管理的方式: