日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

操作系统——内存管理——分段和分页

發(fā)布時間:2023/12/4 windows 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 操作系统——内存管理——分段和分页 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、 物理地址和邏輯地址

物理地址:加載到內(nèi)存地址寄存器中的地址,內(nèi)存單元的真正地址。在前端總線上傳輸?shù)膬?nèi)存地址都是物理內(nèi)存地址,編號從0開始一直到可用物理內(nèi)存的最高端。這些數(shù)字被北橋(Nortbridge chip)映射到實際的內(nèi)存條上。物理地址是明確的、最終用在總線上的編號,不必轉(zhuǎn)換,不必分頁,也沒有特權(quán)級檢查(no translation, no paging, no privilege checks)。

邏輯地址:CPU所生成的地址。邏輯地址是內(nèi)部和編程使用的、并不唯一。例如,你在進行C語言指針編程中,可以讀取指針變量本身值(&操作),實際上這個值就是邏輯地址,它是相對于你當(dāng)前進程數(shù)據(jù)段的地址(偏移地址),不和絕對物理地址相干。

為什么會有這兩種地址?

個人覺的原因在于邏輯地址分配更加靈活,可以允許不唯一,看起來也較為直觀,例如,一段代碼中分配數(shù)組,邏輯地址上是連續(xù)的,然而在物理地址上,這個數(shù)組所占用的頁可能分散開來,物理地址上就是不連續(xù)的,這樣對程序的可理解性上有影響。另外,有了邏輯地址這個概念,才能使用虛擬內(nèi)存技術(shù)。

2、 Paging,分頁內(nèi)存管理方案

2.1 分頁的最大作用就在于:使得進程的物理地址空間可以是非連續(xù)的。

物理內(nèi)存被劃分為一小塊一小塊,每塊被稱為幀(Frame)。分配內(nèi)存時,幀是分配時的最小單位,最少也要給一幀。在邏輯內(nèi)存中,與幀對應(yīng)的概念就是頁(Page)。

邏輯地址的表示方式是:前部分是頁碼后部分是頁偏移。

例如,已知邏輯空間地址為2^m 個字節(jié)(也就是說邏輯地址的長度是m位) ,已知頁大小是 2^n 字節(jié)。那么一共可以有2^(m-n)個頁。因此頁碼部分會占m-n位,之后的n位,用來存儲頁偏移。

舉個例子, 頁大小為4B,而邏輯內(nèi)存為32B(8頁),邏輯地址0的頁號為0,頁號0對應(yīng)幀5,因此邏輯地址映射為物理地址54+0=20。邏輯地址3映射物理地址54+3=23。邏輯地址13(4*3+1,頁號為3,偏移為1,因此幀號為2),映射到物理地址9。

采用分頁技術(shù)不會產(chǎn)生外部碎片(內(nèi)存都被劃分為幀),但可能產(chǎn)生內(nèi)部碎片(幀已經(jīng)是最小單元,因此幀內(nèi)部可能有空間沒有用到)。

按概率計算下來,每個進程平均可有半個幀大小的內(nèi)部碎片。

2.2 頁表的硬件實現(xiàn)

上一小節(jié)中寫到頁表是邏輯地址轉(zhuǎn)化到物理地址的關(guān)鍵所在。那么頁表如何存儲?

每個操作系統(tǒng)都有自己的方法來保存頁表。絕大多數(shù)都會為每個進程分配一個頁表。現(xiàn)在由于頁表都比較大,所以放在內(nèi)存中(以往是放在一組專用寄存器里),其指針存在進程控制塊(PCB)里,當(dāng)進程被調(diào)度程序選中投入運行時,系統(tǒng)將其頁表指針從進程控制塊中取出并送入用戶寄存器中。隨后可以根據(jù)此首地址訪問頁表。

頁表的存儲方式是TBL(Translation look-aside buffer, 翻譯后備緩沖器)+內(nèi)存。TBL實際上是一組硬件緩沖所關(guān)聯(lián)的快速內(nèi)存。若沒有TBL,操作系統(tǒng)需要兩次內(nèi)存訪問來完成邏輯地址到物理地址的轉(zhuǎn)換,訪問頁表算一次,在頁表中查找算一次。TBL中存儲頁表中的一小部分條目,條目以鍵值對方式存儲。

2.3 頁表的數(shù)據(jù)結(jié)構(gòu)

a.

今年是2013年,現(xiàn)有的筆記本電腦,內(nèi)存地址空間一般為2^32 字節(jié)以上。對于具有32位邏輯地址空間的計算機系統(tǒng),如果系統(tǒng)的頁大小為4KB (2^12B) ,那么頁表可以擁有2^(32-12)個,也就是一百多萬個條目,假設(shè)每個條目占有4B,那每個進程都需要4MB的物理地址空間來存放頁表本身。而且,頁表本身需要分配在連續(xù)內(nèi)存中。

為此,Hierarchical Paging(層次化分頁)被提出,實際上就是將頁號分為兩部分,第一部分作為索引,第二部分作為頁號的偏移。

以一個4kb頁大小的32位系統(tǒng)為例。一個邏輯地址被分為20位的頁碼和12位的頁偏移。因為要對頁表進行再分頁,所以該頁號可分為10位的頁碼和10位的頁偏移。這樣一個邏輯地址就表示如下形式:

地址轉(zhuǎn)換過程如下:

地址由外向內(nèi)轉(zhuǎn)換,因此此方法也被稱為forward-mapped page table(向前映射表)。

b. Hashed Page Tables 哈希頁表

處理超過32位地址空間的常用方法是使用hashed page table(哈希頁表),并以虛擬頁碼作為哈希值。哈希頁表的每一條目都包括一個鏈表的元素,這些元素哈希成同一位置。每個元素有三個域:虛擬頁碼,所映射的幀號,指向鏈表中下一個元素的指針。

個人看來,哈希頁表的地址轉(zhuǎn)換方式,實際上是Chaining(鏈接)方式,也就是一種哈希函數(shù)的溢出處理方式(另一種溢出處理方式叫做Open Addressing,開放尋址),具體過程如下:

邏輯地址需要大于32bit的地址空間來表示,但是操作系統(tǒng)仍只有32bit來表示地址。此時人們便想到虛擬頁地址,虛擬地址可以在32bit表示范圍之內(nèi),然后利用哈希函數(shù)完成邏輯地址到虛擬地址的映射,由于虛擬地址更少,哈希函數(shù)會出現(xiàn)溢出,這里使用Chaining來解決溢出。

邏輯地址中的頁號(下圖中的p)經(jīng)過哈希函數(shù)的計算,算出虛擬地址中的頁號,根據(jù)虛擬頁號可以在哈希表中以O(shè)(1)方式尋址,用p與鏈表中的每一個元素的第一個域相比較。如果匹配,那么相應(yīng)的幀號就用來形成物理地址。如果不匹配,就對鏈表中的下一個節(jié)點進行比較,以尋找一個匹配的頁號。

c. Inverted page table 反向頁表

時間關(guān)系,這段暫時略過。

三、 Segmentation,分段內(nèi)存管理方案

采用分頁內(nèi)存管理有一個不可避免的問題:用戶視角的內(nèi)存和實際內(nèi)存的分離。設(shè)想一段main函數(shù)代碼,里面包含Sqrt函數(shù)的調(diào)用。按照編寫者的理解,這段代碼運行時,操作系統(tǒng)應(yīng)該分配內(nèi)存給:符號表(編譯時使用),棧(存放局部變量與函數(shù)參數(shù)值),Sqrt代碼段,主函數(shù)代碼段等。這樣,編寫者就可以方便地指出:“函數(shù)sqrt內(nèi)存模塊的第五條指令”,來定位一個元素。而實際上,由于采用Paging的管理方式,所有的一切都只是散落在物理內(nèi)存中的各個幀上,并不是以編寫者的理解來劃分模塊。

Segmentation的內(nèi)存管理方式可以支持這種思路。邏輯地址空間由一組段組成。每個段都有名字和長度。地址指定了段名稱和段內(nèi)偏移。因此用戶通過兩個量來指定地址:段名稱和偏移。段是編號的,通過段號而非段名稱來引用。因此邏輯地址由有序?qū)?gòu)成:

<segment-number,offset>(<段號s, 段內(nèi)偏移d>)

段偏移d因該在0和段界限之間,如果合法,那么就與基地址相加而得到所需字節(jié)在物理內(nèi)存中的地址。因此段表是一組基地址和界限寄存器對。

例如下圖,有5個段,編號0~4,例如段2為400B開始于位置4300,對段2第53字節(jié)的引用映射成位置4300+53=4353。而段0字節(jié)1222的引用則會觸發(fā)地址錯誤,因為該段的僅為1000B長(界限為1000)。

4、 合并分段和分頁的管理方案

在現(xiàn)有的Intel兼容計算機(x86)上,采用的內(nèi)存管理方案是分段和分頁合并的管理方案。

在這個方案中,邏輯地址,如前一節(jié)中所說,是由一個段標(biāo)識符加上一個指定段內(nèi)相對地址的偏移量,表示為 [段標(biāo)識符:段內(nèi)偏移量]。

這樣的邏輯地址轉(zhuǎn)換的過程是怎樣呢?如下圖所示:

當(dāng)CPU要執(zhí)行一條引用了內(nèi)存地址的指令時,轉(zhuǎn)換過程就開始了。第一步是把邏輯地址轉(zhuǎn)換成線性地址。但是,為什么不跳過這一步,而讓軟件直接使用線性地址(或物理地址呢?)原因主要是因為:

(1) Intel的更新是漸進式而非革命式,新的處理器需要兼容和保留過往的設(shè)置。具體的原因,博文Memory Translation and Segmentation (http://blog.csdn.net/drshenlei/article/details/4261909) 中講的較為清楚。

(2) 如上節(jié)所說,采用段內(nèi)存管理,可以跟方便地進行地址保護(同一類型的地址邏輯地址在一起)。

下面講邏輯地址到線性地址的部分。

在IBM OS/2 32位版本的操作系統(tǒng),和Intel 386的環(huán)境下。操作系統(tǒng)采用的內(nèi)存分配方式就是分段和分頁合并的方式。

邏輯地址的實際上是一對<選擇符,偏移>。

選擇符的內(nèi)容如下:

從左開始,13位是索引(或者稱為段號),通過這個索引,可以定位到段描述符(segment descriptor),而段描述符是可以真正記載了有關(guān)一個段的位置和大小信息, 以及訪問控制的狀態(tài)信息。段描述符一般由8個字節(jié)組成。由于8B較大,而Intel為了保持向后兼容,將段寄存器仍然規(guī)定為16-bit(盡管每個段寄存器事實上有一個64-bit長的不可見部分,但對于程序員來說,段寄存器就是16-bit的),那么很明顯,我們無法通過16-bit長度的段寄存器來直接引用64-bit的段描述符。因此在邏輯地址中,只用13bit記錄其索引。而真正的段描述符,被放于數(shù)組之中。

這個內(nèi)存中的數(shù)組就叫做GDT(Global Descriptor Table,全局描述表),Intel的設(shè)計者門提供了一個寄存器GDTR用來存放GDT的入口地址。程序員將GDT設(shè)定在內(nèi)存中某個位置之后,可以通過LGDT指令將GDT的入口地址裝入此寄存器,從此以后,CPU就根據(jù)此寄存器中的內(nèi)容作為GDT的入口來訪問GDT了。

除了GDT之外,還有LDT(Local Descriptor Table,本地描述表),但與GDT不同的是,LDT在系統(tǒng)中可以存在多個,每個進程可以擁有自己的LDT。LDT的內(nèi)存地址在LDTR寄存器中。

在之前圖中的TI位,就是用來表示此索引所指向的段描述符是存于全局描述表中,還是本地描述表中。=0,表示用GDT,=1表示用LDT。

RPL位,占2bit,是保護信息位,還沒有仔細了解過這一塊,暫時先不寫。

找到,段描述符后,加上偏移量,便是線性地址。轉(zhuǎn)換過程如下:

在Intel 386的環(huán)境下,線性地址轉(zhuǎn)換為物理地址的過程,和第二節(jié)分頁式內(nèi)存管理中,層次分頁中,邏輯地址轉(zhuǎn)換為物理地址的方法類似。如下圖。

Intel 80386的地址轉(zhuǎn)換全過程如下圖:

本文來自:https://www.cnblogs.com/felixfang/p/3420462.html

總結(jié)

以上是生活随笔為你收集整理的操作系统——内存管理——分段和分页的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。