0x12 內存管理(一)

長篇預警

一、內存管理背景

內存是現代計算機運行的中心,它是由字或字節組成,每個字或字節都有自己的地址。

基本硬件

程序必須裝入內存才能被執行
CPU可以直接訪問的存儲器只有主存、高速緩存和寄存器
寄存器通常可在1個(或少於1個)CPU時鐘週期內完成訪問,完成主存訪問可能需要多個CPU時鐘週期;
CPU暫停(Stall):在讀取內存數據時,CPU空閒;
在內存和CPU之間,增加高速內存,來協調速度差異,這種內存緩衝區稱爲高速緩存Cache;
內存保護需要保證正確的操作。

獨立運行內存空間

確保進程可訪問的合法地址範圍,並確保進程只訪問其合法地址。
兩個寄存器實現進程保護:

  • 基址寄存器(Base)
    進程最小的合法物理內存地址
  • 界限寄存器(Limit)
    進程地址的長度
  • CPU在執行指令時,需要進行地址合法性檢驗
    在這裏插入圖片描述
    合法的地址應該是大於等於基址寄存器的值,小於基址與界限寄存器的值之和。否則將陷入操作系統內核,作爲尋址錯誤處理。

指令和數據綁定到內存

程序以二進制可執行文件的形式存儲在磁盤上,爲了執行,程序被調入內存並放在進程空間內。

地址綁定(重定位):在秩序裝入內存時,把程序中的相對地址轉換爲內存中的絕對地址的過程。

指令和數據綁定到內存地址可在三個不同階段:

  1. 編譯時期(Compile time)
    如果內存位置已知,可生成絕對代碼;
    如果開始位置改變,需要重新編譯代碼
  2. 加載時期(Load time)
    如果存儲位置在編譯時不知,則必鬚生成可重定位(relocatable)代碼
  3. 執行時期(Execution time)
    如果進程執行時可在內存移動,則地址綁定可延遲到運行時;
    需要硬件對地址映射的支持(例如基址和限長寄存器)
    在這裏插入圖片描述

邏輯地址和物理地址

邏輯地址
由CPU產生,在進程內的相對地址,也稱虛擬地址、相對地址、程序地址;
物理地址
內存地址,所有內存統一編址,也稱絕對地址、實地址。

編譯和加載時的地址綁定生成相同的邏輯地址和物理地址,此時重定位是靜態的;但執行時的地址綁定導致不同的邏輯地址和物理地址,此時的重定位稱爲動態重定位
由程序所生成的所有邏輯地址的集合稱爲邏輯地址空間,與這些邏輯地址所對應的所有物理地址的集合稱爲物理地址空間。
邏輯地址空間綁定到物理地址空間這一概念至關重要,是正確進行內存管理的中心。

內存管理單元(MMU)

運行時,從虛擬地址到物理地址的映射是由一個硬件設備來完成的。該硬件稱爲內存管理單元(簡稱MMU)。它是CPU用來管理內存的控制線路。

在這裏插入圖片描述
實現地址映射,在MMU策略中,這裏的基址寄存器稱爲重定位寄存器,這裏的重定位就是指從邏輯地址轉化爲物理地址的過程。邏輯地址在送入內存之前要加上重定位寄存器的值。用戶程序所對應到的是邏輯地址,物理地址從來都不可見。
在這裏插入圖片描述

動態加載

爲了獲得更好的內存空間使用率,可以使用動態加載。
一個子程序只有在被調用時纔會加載;
不需要操作系統的特別支持,通過程序設計實現。

優點:

  • 更好的內存空間利用率
  • 沒有被使用的例程不被載入
  • 當需大量代碼來處理不經常使用的功能時非常有用
    操作系統可以提供子程序庫來幫助加載,如Windows的動態鏈接庫。

動態鏈接

  • 和各種庫文件的鏈接被推遲到執行時期
  • 需要動態裝載技術支持
  • 一小段代碼即存根。用來定位合適的保留在內存中的庫程序
  • 存根用例程地址來替換自己,並開始執行例程
  • 操作系統需要檢查例程是否在進程的內存空間,所以需要操作系統支持

二、連續內存分配

爲一個用戶程序分配一個連續的內存空間。
早期內存分配模式:應用於內存較小的系統

三種類型:

  1. 單一連續分配
  2. 固定分區分配
  3. 可變分區分配

主存通常被分爲兩部分:

  • 操作系統(通常駐留在低端,因爲中斷矢量保存在低端)
  • 用戶進程(保存在內存高端)

1. 單一連續分配

分配方式:單道程序環境下,僅裝有一道用戶程序,即整個內存的用戶空間由該程序獨佔。

  • 內存分配管理十分簡單,內存利用率低
  • 適用於單用戶、單任務OS
  • CP/M、MS-DOS、RT11

未採取存儲器保護措施

  • 節省硬件
  • 方案可行

2. 固定分區分配

最早的、也是最簡單的一種可運行多道程序的存儲管理方式;
預先把可分配的主存空間分割成若干個連續區域,稱爲一個分區;
每個分區的大小可以相同也可以不同。但分區大小一旦固定就不能改變,每個分區裝一個且只能裝一個程序,因此多道程序的道數受分區個數的限制;
內存分配:如果有一個空閒分區,則分配給進程。

劃分分區的方法:

  1. 分區大小一樣
    缺乏靈活性。程序太小:浪費內存;程序太大:裝不下。
    有些場合適用,如利用一臺計算機同時控制多個相同對象。

  2. 分區大小不等

  • 多個小分區
  • 適量中分區
  • 少量大分區

3. 可變分區分配

可變分區是固定分區方案的延伸,主要用於批處理環境。

  • 分區(孔、Hole)-可用的內存塊,不同大小的分區分佈在整個內存中;
  • 當一個進程到來的時候,它將從一個足夠容納它分區中分配內存。
  • 操作系統包含以下信息:
    a)已分配的分區-已分配分區表
    b)空的分區-空閒分區表
    具體實現的數據結構可以是線性表或鏈表

在這裏插入圖片描述
從圖上可以看到,進程8終止,所佔內存被釋放,進程9,10佔用了部分內存。

可變分區分配是動態存儲分配問題的一種情況。

存儲分配算法

  1. 首次適應(First-fit):分配最先找到的合適的分區;
  2. 最佳適應(Best-fit):搜索整個列表,找到適合條件的最小的分區進行分配;
  3. 最差適應(Worst-fit):搜索整個列表,尋找最大的分區,進行分配。

現有一進程請求分配110K內存,首次適應、最佳適應、最差適應的分配方法如下:
在這裏插入圖片描述
在速度和存儲空間的利用上,首次適應法和最佳適應法要好於最差適應法,首次適應法和最佳適應法在空間利用上差不多,但首次適應法更快些

內存回收

可變分區分配方案的內存回收存在4種情況:
a. 回收內存塊前後無空閒塊
直接增加回收區爲新的空閒塊;

b. 回收內存塊前有後無空閒塊
空閒塊F1和回收區合併成一個空閒塊,該空閒塊的起始地址爲F1的地址,大小爲兩者之和;

c. 回收內存塊前無後有空閒塊
回收區和空閒塊F2合併成一個空閒塊,該空閒塊的起始地址爲回收區的地址,大小爲兩者之和;

d. 回收內存塊前後均有空閒塊
空閒塊F1和回收區、空閒塊F2合併成一個空閒塊,該空閒塊的起始地址爲F1的地址,大小爲三者之和;

在這裏插入圖片描述

碎片

隨着進程頒繁的裝入和移出內存,空閒內存空間中可能被分成小的片段。

  • 外碎片——整個可用內存空間可以用來滿足一個請求,但它不是連續的,就出現了外碎片問題。
    首次適應法和最佳適應法都有這個問題,這個問題可能很嚴重,最壞情況下,每兩個進程之間都有空閒塊被浪費。
  • 內碎片——在固定分區分配方案中,分配的內存可能比申請的內存大一點,這兩者之間的數字差被稱爲內碎片,這部分內存是在分區內部,但又不被使用。

可通過緊縮來減少外碎片:把一些小的空閒內存結合成一個大的塊。只有重定位是動態並且運行的時候,纔有可能進行緊縮,緊縮在執行時期進行。

最簡單的合併算法是簡單地將所有進程移動到內存的一端,而所有空閒分區移到另一端,這種方法的開銷較大,所以爲減少開銷,應選擇移動內容最小的一種。

緊縮例子:
右邊3個是緊縮之後的內存空間,分別移動600K,400K,200K。
在這裏插入圖片描述

三、分頁內存管理

解決外碎片的方案:允許物理地址空間非連續。

離散內存管理方案

  1. 分頁內存管理方案——現代操作系統常用方案
  2. 分段內存管理方案
  3. 段頁式內存管理方案

分頁

內存管理方案允許進程的物理地址空間可能不連續。只要有可用的物理內存,就可以分配給進程。

基本方法:

物理內存分成大小固定的塊,稱爲(frame)。也可以簡單稱爲內存塊,又稱爲頁框;
邏輯內存也分爲同樣大小的塊,稱爲頁

幀和頁的大小是由硬件來決定的,通常爲2的冪。根據計算機結構的不同,大小不同。
早期爲512字節至8K字節。現在爲4K-64K。

系統保留所有空閒幀的記錄。運行一個有N頁大小程序,需要找到N個空幀來裝入程序。
系統將建立一張頁表,記錄頁與幀之間的映射關係。進程運行時,通過查找頁表,實現邏輯地址轉換爲物理地址。

分頁由硬件來處理的。然而,最新的設計是通過將硬件和操作系統相配合來實現的(尤其是在64位的微處理器上)。
採用分頁技術不會產生外碎片,因爲每個幀都可以分配給選程;分頁有內碎片,進程請求的內存可能不是頁的整數倍,因此最後一幀中可能存在多餘的內存空間。

邏輯內存和物理內存的分頁模型

在這裏插入圖片描述

地址轉換機制

分頁地址被分爲:

  • 頁號(p)——它包含每個頁在物理內存中的基址,用來爲頁表的索引;
  • 頁偏移(d)——同基址相結合,用來確定送入內存設備的物理內存地址。
    在這裏插入圖片描述
    我們稱上圖的邏輯地址爲線性地址

分頁的硬件支持

1)根據邏輯地址中的頁號p,到頁表中找到第p項,第p項內存儲的f就是頁框號;
2)頁框號f和頁內偏移d構成物理地址。

在這裏插入圖片描述
在這裏插入圖片描述
根據上圖,頁大小:4字節;
物理內存:32字節;
邏輯內存:4頁。

通過查頁表,
20 = 5*4+0,邏輯內存0映射爲物理內存20;
25 = 6*4+1,邏輯內存1映射爲物理內存25。

操作系統通過一個數據結構來管理物理內存中的空閒幀。這個結構稱爲空閒幀表,保存系統中所有的空閒幀。

空閒幀的分配:
當進程需要n頁。如果系統有至少n幀,那麼就分配給新進程。
在這裏插入圖片描述

頁表的實現

頁表的硬件實現:
當頁表較小時,可放入專用寄存器。
將頁表保存在內存中,並將頁表基址寄存器(PTBR)指向頁表,頁表限長寄存器(PRLR)表明頁表的長度。
在這個機制中,每一次的數據/指令存取需要兩次內存存取,一次是存取頁表,一次是存取數據/指令。這樣內存訪問速度會減半。
解決兩次存取的問題,是採用小但專用且快速的硬件緩衝,這種緩衝稱爲轉換表緩衝器(TLB)或聯想寄存器

TLB/聯想寄存器的條目組成:
鍵、值實現並行查找
這種查找方式比較快,但硬件也比較昂貴。所以通常TLB的條目數並不多,通常在64~1024之間。

使用TLB的分頁硬件:
在這裏插入圖片描述

頁號在TLB中被查找到的百分比稱爲命中率。這個比率與TLB的大小有關。

爲了衡量聯想寄存器的效率,引入了有效訪問時間。
有效訪問時間(EAT):
根據概率對每種情況進行加權得到,類似於平均訪問時間。
假設查找聯想寄存器需要時間爲a,內存一次存取時間爲b,命中率爲λ,則有效訪問時間:
EAT=λ(a+b)+(1-λ)(a+2b)

例如,查找TLB需要20ns,訪問內存需要100ns,命中率爲80%,如果在TLB命中,那麼需要120ns;如果未命中,那麼需要2次內存訪問時間加上TLB訪問時間,所以一共需要220ns。
EAT = 0.8*120+0.2*220=140ns
內存訪問速度從100ns到140ns,減慢了40%;
如果命中率爲98%,可計算出EAT=122ns,內存訪問速度只慢了22%。

內存保護

簡單方法:把頁號和頁表限長寄存器值相比較;
細緻方法:通過與每個幀相關聯的保護位來實現的

有效-無效位附在頁表的每個表項中:

  • “有效”表示相關的頁在進程的邏輯地址空間,並且是一個合法的頁;
  • “無效”表示頁不在進程的邏輯地址空間中。

通過有效-無效位可以捕捉到非法地址,操作系統可以通過對該位的設置來允許或不允許對某頁的訪問。
在這裏插入圖片描述
例如上圖,有效地址空間爲0~10468,如果頁的大小爲2KB。
頁表的0-5是有效的,6,7無效,如果要訪問這兩頁的地址,將產生非法操作。還有由於程序地址只到10468,所以超過該地址的引用都是非法的。但由於對頁5的訪問是有效的,因此到12287爲止的地址都是有效的。這個問題是由頁內碎片的存在而引起的。

分頁的優點

可以共享公共代碼,如果代碼是可重入代碼(或稱爲純代碼),則可以在進程間共享(如文本編輯器,編譯器,數據庫系統)。可重入代碼是不可自我修改的代碼,不會在執行期間改變。

共享代碼必須出現在所有進程的邏輯地址空間的相同位置。

每個進程單獨保留一個代碼和數據的副本,還可以有自己的私有代碼和數據,存有這些數據的頁能夠出現在邏輯空間的任意位置。

下一篇 內存管理(二)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章