內存概述
什麼是內存:
內存是用於存放數據的硬件,程序執行前需要先放到內存中才能被CPU處理。
存儲單元
將內存分爲一個一個的小區間,每個區間就是一個存儲單元。
內存地址
給內存的存儲單元編地址,有兩種:
- 按字節編址:每個存儲單元的大小爲1字節(8位)
- 按字編址:字長爲16位的計算機,每個存儲單元的大小爲1個字(16位)
邏輯地址和物理地址
- 邏輯地址:編譯生成的指令中是邏輯地址,是相對地址。
- 物理地址:是數據實際存放在內存當中的地址,是絕對地址。
進程運行的基本原理
進程執行的流程:
裝入方式
- 絕對裝入: 在編譯時,如果直到程序將放到內存中的哪個位置,編譯時將產生絕對地址的目標代碼,裝入程序按照裝入模塊中的地址,將程序和數據裝入內存。
缺點:只適合單道程序環境。 - 靜態重定位: 編譯、鏈接後的裝入模塊的地址都是從0開始,指令中也是邏輯地址。在裝入時對地址進行重定位,將邏輯地址變換爲物理地址。
缺點:內存必須有足夠的空間才能裝入該進程,且運行期間不能移動。 - 動態重定位: 使用重定位寄存器,當該進程被調度運行時,纔會獲取寄存器中的信息,將邏輯地址轉換爲物理地址。
優點:運行期間也可移動。
鏈接方式
- 靜態鏈接: 在程序運行前,將個目標模塊鏈接成一個完整的裝入模塊,之後不可拆分。
- 裝入時動態鏈接: 將各目標模塊裝入內存時,邊裝入邊鏈接。
- 運行時動態鏈接: 在程序執行中需要該目標模塊時,纔對它進行鏈接。
內存管理*
內存管理的主要內容:
- 地址轉換: 對應三種裝入方式
- 存儲保護: 保證各進程在自己的內存空間內運行,不會越界訪問,兩種方式:
1.設置上下限寄存器
2.重定位寄存器+界地址寄存器 - 內存空間的擴充(虛擬)
- 內存空間的分配與回收
內存空間的擴充
- 覆蓋技術:將程序分爲多個段,常用的段常駐內存,不常用的段在需要時調入內存(固定區,覆蓋區)。
- 交換技術:內存空間緊張時,系統會將內存中某些進程暫時換出外存,外存中已具備運行條件的進程換入內存(中級調度)。
- 虛擬存儲技術:後文
注:磁盤空間分爲文件區和對換區,文件區採用離散分配方式,對換區採用連續分配方式。
內存空間的分配與回收
兩種類型分配方式:
- 連續分配管理:用戶進程分配的必須是一個連續的內存空間
- 非連續分配管理
連續分配管理
- 單一連續分配:
內存分爲系統區和用戶區,內存中只能有一道用戶程序。 - 固定分區分配:
用戶區劃分爲若干個固定大小的分區(分區大小相等/不相等),每個分區可裝入一道作業。
需要建立分區說明表:分區大小、起始地址、狀態 - 動態分區分配:
在進程裝入內存時,根據進程的大小動態地建立分區。
需要建立空閒分區表或空閒分區鏈:
內部碎片: 分配給某個進程的內存區域中,有些部分沒用上。
外部碎片: 內存中的某些空閒分區由於太小而難以利用。我們一般通過緊湊技術來解決外部碎片。
動態分區分配算法
當多個空閒分區都滿足進程大小需求時,需要選擇分區,因此有以下四中分配算法:
- 首次適應算法
空閒分區以地址遞增的次序排列,順序查找到第一個能滿足的空閒分區。 - 最佳適應算法
空閒分區以容量遞增的次序排列,順序查找到第一個能滿足的空閒分區。 - 最壞適應算法
空閒分區以容量遞減的次序排列,順序查找到第一個能滿足的空閒分區。 - 鄰近適應算法
空閒分區以地址遞增的次序排列,從上次查找結束的位置開始查找,找到第一個滿足要求的空閒分區。
非連續分配管理*
連續分配:爲用戶進程分配的必須是一個連續的內存空間。
非連續分配:爲用戶進程分配的可以是一些分散的內存空間。
三種管理方式:
- 基本分頁存儲管理
- 基本分段存儲管理
- 段頁式存儲管理
基本分頁存儲管理
基本思想
把內存分爲一個個相等的小分區,再按照分區大小把進程拆分成一個個小部分。
基本概念
- 內存空間中每個分區被稱爲頁框(頁幀/內存塊/物理塊),每個頁框有一個編號(從0開始),被稱爲頁框號(內存塊號/頁幀號/物理塊號)。
- 用戶進程的地址空間劃分爲與頁框大小相等的一個個區域,被稱爲頁(面),也有一個編號,即頁號。
- 操作系統以頁框爲單位爲各個進程分配內存空間,即頁面與頁框一一對應。
那如何知道進程的每個頁面在內存中存放的位置,就要爲每個進程建立一張頁表,如下:
如何得到物理地址
- 算出邏輯地址對應的頁號
- 要知道該頁號對應頁面在內存中的起始地址
- 要算出路基地址在頁面內的“偏移量”
- 物理地址 = 頁面始址 + 頁內偏移量
上面是我們的實現邏輯地址到物理地址轉換的原理,而實際上是由基本地址變換機構(用於實現邏輯地址到物理地址轉換的一組硬件機構)來實現的。
通常會在系統中設置一個頁表寄存器,存放頁表在內存中的起始地址 F 和頁表長度 M,進程未執行時,F 和 M 放在進程控制塊 PCB 中。
優化
- 快表
在基本地址變換機構中,每個邏輯地址都要查詢內存中的頁表,而快表(聯想寄存器)是一種訪問速度比內存快的高速緩衝存儲器,用來存放當前訪問的若干頁表項,以加快地址變換的過程。 - 二級頁表
頁表一般連續存放且沒必要整個頁表常駐內存,因此可以使用二級頁表,即在原本頁表的基礎上,加一個頁目錄表,如下:
基本分段存儲管理
基本思想
按照程序自身的邏輯關係劃分爲若干段,每個段都有一個段名且從0開始編址;每段在內存中佔據連續空間,各段之間可以不相鄰。
分段系統的邏輯地址由段號(段名)和段內地址(偏移量)組成,同樣需要爲每個進程建立一張段映射表,即段表:
分段與分頁對比
- 頁是信息的物理單位,是系統的行爲,對用戶不可見
- 段時信息的邏輯單位,是用戶編程是決定,對用戶是可見的
- 分頁的邏輯地址是一維的,而分段的邏輯地址是二維的
- 分段比分頁更容易實現信息的共享和包含
段頁式管理方式
先來看下分頁管理和分段管理的特點:
優點 | 缺點 | |
---|---|---|
分頁管理 | 內存利用率高,不會產生外部碎片 | 不易實現信息的共享和保護 |
分段管理 | 方便實現信息共享和保護 | 段太長,不易分配連續空間,且會產生外部碎片 |
段頁式管理 = 分段 + 分頁
進程先分段,再將各段分爲大小相等的頁面
內存空間分爲與頁面大小相等的一個個內存塊,系統以塊爲單位爲進程分配內存,如下:
同時會存在段表和頁表:
- 段表:每段對應一個段表項,各段表項長度相同,由段號、頁表長度、頁表地址組成。
- 頁表:每頁對應一個頁表項,各頁表項長度相同,由頁號、頁面存放的內存塊號組成。
虛擬內存
傳統存儲管理的缺點:
- 一次性,即作業必須一次性全部裝入內存後才能開始運行。
- 駐留性,即一旦作業被裝入內存,就會一直駐留在內存中,直到作業運行結束。
虛擬內存技術
允許一個作業分多次調入內存,虛擬內存的實現需要建立在離散分配的內存管理方式基礎上,對應三種非連續分配:
請求調頁:訪問的信息不在內存時,由操作系統負責將所需信息從外存調入內存。
頁面置換:內存空間不夠時,由操作系統將內存中暫時用不到的信息換出到外存。
請求分頁
頁表機制
請求頁表項增加了四個字段:
缺頁中斷機構
每當要訪問的頁面不在內存時,便會產生一個缺頁中斷,然後由操作系統的缺頁中斷處理程序處理中斷。
缺頁的進程會阻塞,調頁完成後才喚醒。
內存中有空閒塊就直接給該進程分配一個空閒塊,如果沒有則由頁面置換算法淘汰一個頁面。
缺頁中斷是因爲當前指令想要訪問的目標頁面未調入內存,因此屬於內中斷。
地址變換機構
區別與基本分頁:
- 檢查頁面是否在內存中
- 若不在內存中,需要請求調頁
- 若內存空間不夠,還需換出頁面
- 頁面調入內存後,需要修改相應頁表項
頁面置換算法
頁面的換入、換出需要磁盤I/O,會有較大的開銷,因此算法應該追求更少的缺頁率。
最佳置換算法 OPT
每次選擇淘汰的頁面將是以後永不使用,或者在最長時間內不再被訪問的頁面。
因爲系統需要知道以後會出現的頁面,所以是無法實現的。
先進先出置換算法 FIFO
每次選擇淘汰的頁面是最早進入內存的頁面。
只有 FIFO 算法會產生 Belady 異常。
Belady 異常:爲進程分配的物理塊數增大時,缺頁次數不減反增的異常現象。
FIFO 算法實現簡單,但是性能差。
最近最久未使用置換算法 LRU
每次淘汰的頁面是最近最久未使用的頁面。
實現:頁表增加訪問字段,記錄每個頁面自上次被訪問依賴所經歷的時間 t,每次選擇現有頁面中 t 值最大的。
最接近 OPT 性能的算法,但是需要專門的硬件支持,算法開銷大。
時鐘置換算法 CLOCK
性能和開銷均衡的算法,又稱爲最近未用算法(NRU)。
實現:
- 每個頁面設置一個訪問位(1/0),再將內存中的頁面通過鏈接指針鏈接成一個循環隊列。
- 當某頁被訪問時,訪問位爲 1。
- 當淘汰某個頁面時,只需檢查頁的訪問位,如果是 0,則換出;如果是 1,置 0,暫不換出並檢查下一個。
- 若第一輪掃描所有頁面是 1,則都置 0 後會進行第二輪掃描。
改進型的時鐘置換算法
上面的時鐘置換算法其實少考慮了一種情況,就是頁面是否被修改過。
所以需要檢查訪問位和修改位,用(訪問位,修改位)表示,過程如下:
- 第一輪,淘汰 (0,0),即未被使用和修改的頁面
- 第二輪,淘汰 (0,1),即未被使用的頁面,並將掃描過的頁面訪問位置 0
- 第三輪,淘汰 (0,0),即未被修改的頁面
- 第四輪,淘汰 (0,1),即最早進入隊列的頁面
頁面分配策略
駐留集:指請求分頁存儲管理中給進程分配的內存塊的集合。
工作集:指再某段時間間隔裏,進程實際訪問頁面的集合。
駐留集一般小於進程的總大小,駐留集大小一般不能小於工作集大小。
固定分配: 操作系統爲每個進程分配一組固定的物理塊,即駐留集大小不變。
可變分配: 先爲每個進程分配一定數目的物理塊,在進程運行期間根據情況做適當的調整,即駐留集大小可變
局部置換: 發生缺頁時只能選進程自己的物理塊進行置換。
全局置換: 可以將操作系統保留的空閒物理塊分配給缺頁進程,也可以將別的進程持有的物理塊置換到外存,再分配給缺頁進程。
所以根據以上四種,可以有一下組合:
- 固定分配局部置換
發生缺頁只能從自己的進程在內存中的頁面選出一頁換出。 - 可變分配全局置換
只要缺頁就給分配新物理塊(空閒塊/未鎖定頁面的內存塊),缺頁率會增加。 - 可變分配局部置換
根據發生缺頁的頻率來動態地增加或減少進程的物理塊。
預調頁策略: 在進程運行前,調入若干個可能訪問到的頁面,主要用於進程的首次調入。
請求調頁策略: 進程在運行期間發現缺頁時纔將所缺頁面調入內存。
抖動(顛簸)現象:
剛剛換出的頁面馬上又要換入內存,剛剛換入的頁面又要換出外存,這種頻繁的頁面調度行爲稱爲抖動或顛簸,產生顛簸的主要原因是進程頻繁訪問的頁面數目高於可用的物理塊數。