www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > IOT物聯(lián)網(wǎng)小鎮(zhèn)
[導(dǎo)讀]作?者:道哥,10年嵌入式開(kāi)發(fā)老兵,專注于:C/C、嵌入式、Linux。關(guān)注下方公眾號(hào),回復(fù)【書(shū)籍】,獲取Linux、嵌入式領(lǐng)域經(jīng)典書(shū)籍;回復(fù)【PDF】,獲取所有原創(chuàng)文章(PDF格式)。目錄分段存儲(chǔ)的壞處物理內(nèi)存的管理映射表一個(gè)線性地址的尋址過(guò)程終于開(kāi)始介紹分頁(yè)機(jī)制了,作為一名L...

作  者:道哥,10 年嵌入式開(kāi)發(fā)老兵,專注于:C/C 、嵌入式、Linux。


關(guān)注下方公眾號(hào),回復(fù)【書(shū)籍】,獲取 Linux、嵌入式領(lǐng)域經(jīng)典書(shū)籍;回復(fù)【PDF】,獲取所有原創(chuàng)文章( PDF 格式)。


目錄


  • 分段存儲(chǔ)的壞處


  • 物理內(nèi)存的管理


  • 映射表


  • 一個(gè)線性地址的尋址過(guò)程



終于開(kāi)始介紹分頁(yè)機(jī)制了,作為一名Linuxer,大名鼎鼎的分頁(yè)機(jī)制必須要徹底搞懂!


我就盡自己的最大努力,正確把我理解的分頁(yè)機(jī)制,用圖文形式徹底分解,希望對(duì)您有所幫助!


一共分 3 篇文章:


這篇文章主要介紹單映射表;


下一篇介紹兩級(jí)映射(頁(yè)目錄和頁(yè)表);


最后一篇介紹對(duì)映射表自身的操作。


分段存儲(chǔ)的壞處

在之前的文章中,我們多次描寫(xiě)了一個(gè)段描述符的結(jié)構(gòu),其中就包括段的開(kāi)始地址界限和各種段的屬性。


經(jīng)過(guò)分段處理單元的權(quán)限檢查和計(jì)算,這個(gè)開(kāi)始地址加上偏移量,就是一個(gè)線性地址,如下圖所示:


Linux從頭學(xué)14:【分頁(yè)機(jī)制】-看了這篇文章還沒(méi)徹底搞懂?我自罰三杯!在x86系統(tǒng)中,分段機(jī)制是固有的,必須經(jīng)過(guò)這個(gè)環(huán)節(jié)才能得到一個(gè)線性地址。


所以 Linux 系統(tǒng)中,為了“不使用”分段機(jī)制,但是又無(wú)法繞過(guò),只好定義了“平坦”的分段模型。


在沒(méi)有開(kāi)啟分頁(yè)機(jī)制的情況下,分段單元輸出的線性地址就等于物理地址。


這里就存在著一個(gè)重要的問(wèn)題:從段的開(kāi)始地址,一直到段空間的最后地址,這是一塊連續(xù)的空間!


在這樣的情況下,每一個(gè)用戶程序中,包含的所有段,在物理內(nèi)存上所對(duì)應(yīng)的空間也必須是連續(xù)的,如下圖:


Linux從頭學(xué)14:【分頁(yè)機(jī)制】-看了這篇文章還沒(méi)徹底搞懂?我自罰三杯!因?yàn)槊恳粋€(gè)程序的代碼、數(shù)據(jù)長(zhǎng)度都是不確定、不一樣的,按照這樣的映射方式,物理內(nèi)存將會(huì)被分割成各種離散的、大小不同的塊。


經(jīng)過(guò)一段運(yùn)行時(shí)間之后,有些程序會(huì)退出,那么它們占據(jù)的物理內(nèi)存空間可以被回收,但是,這些物理內(nèi)存都是以很多碎片的形式存在。


如果這個(gè)時(shí)候操作系統(tǒng)想分配一塊稍微大一些的連續(xù)空間,雖然空閑的物理內(nèi)存空間總數(shù)是足夠的,但是不連續(xù)啊,這就給物理內(nèi)存帶來(lái)極大的浪費(fèi)!


怎么辦?


現(xiàn)在的需求是:操作系統(tǒng)提供給用戶的段空間必須是連續(xù)的,但是物理內(nèi)存最好不要連續(xù)。


軟件領(lǐng)域有一句經(jīng)典名言:沒(méi)有什么是不能通過(guò)增加一個(gè)抽象層解決的!


在內(nèi)存管理上,新加的這一層就是虛擬內(nèi)存:把物理內(nèi)存按照一個(gè)固定的單位(4 KB,稱作一個(gè)物理頁(yè))進(jìn)行分割,然后把連續(xù)的虛擬內(nèi)存,映射到若干個(gè)不連續(xù)的物理內(nèi)存頁(yè)。


Linux從頭學(xué)14:【分頁(yè)機(jī)制】-看了這篇文章還沒(méi)徹底搞懂?我自罰三杯!圖中綠色的的映射表,就是用來(lái)把虛擬內(nèi)存,映射到物理內(nèi)存。


物理內(nèi)存的管理

關(guān)于映射表的細(xì)節(jié),下一個(gè)主題再聊,先來(lái)看一下操作系統(tǒng)對(duì)物理內(nèi)存的狀態(tài)管理。


在如今的一臺(tái)PC機(jī)上,內(nèi)存動(dòng)輒就是是8G/16G/32G的配置,好像很充裕、隨便用。


但是在 N 年以前,買一個(gè)U 盤(pán)都是按照MB為單位的,更別說(shuō)內(nèi)存了。


因此在那個(gè)時(shí)代,面對(duì)MB級(jí)別的物理內(nèi)存,操作系統(tǒng)還能夠把它虛擬成4GB的內(nèi)存空間給用戶程序使用,也是挺厲害的!


言歸正傳,在這篇文章中,我們就奢侈一點(diǎn),假設(shè)可用的物理內(nèi)存有1GB的空間。


當(dāng)系統(tǒng)上電之后,BIOS會(huì)檢查系統(tǒng)的各種硬件資源,并告訴操作系統(tǒng),其中就包括這1GB的物理內(nèi)存。


按照一個(gè)物理頁(yè)的大小4KB進(jìn)行劃分,1 GB的空間就是262144 (1GB / 4K)個(gè)物理頁(yè)。


操作系統(tǒng)需要對(duì)這些頁(yè)進(jìn)行管理,也就是維護(hù)它們的狀態(tài):哪些頁(yè)正在被使用,哪些頁(yè)空閑


最簡(jiǎn)單、直觀的方法,就是用一塊連續(xù)的內(nèi)存空間來(lái)描述每一個(gè)物理頁(yè)的狀態(tài),每一個(gè)bit位對(duì)應(yīng)一個(gè)物理頁(yè):


bit = 1: 表示該物理頁(yè)被使用;


bit = 0:表示該物理頁(yè)空閑;


262144個(gè)頁(yè)需要262144個(gè)bit位,也就是32768個(gè)字節(jié)。


那么對(duì)于1 GB大小的物理內(nèi)存來(lái)說(shuō),如下圖所示:


Linux從頭學(xué)14:【分頁(yè)機(jī)制】-看了這篇文章還沒(méi)徹底搞懂?我自罰三杯!利用map結(jié)構(gòu),操作系統(tǒng)就知道當(dāng)前: 哪些物理頁(yè)正在被使用,哪些物理頁(yè)是空閑的。


  1. 每一個(gè)物理頁(yè)是 4KB,所以地址中最后 12 個(gè) bit 都是 0;


  2. map 結(jié)構(gòu)本身也需要存儲(chǔ)在物理內(nèi)存中的,因此 32768 個(gè)字節(jié),一共需要 8 個(gè)物理頁(yè)來(lái)存儲(chǔ)(32768 / 4 * 1024 = 8)。


映射表

在32位系統(tǒng)中,虛擬內(nèi)存的最大空間是4GB,這是每一個(gè)用戶程序都擁有的虛擬內(nèi)存空間。


  1. 實(shí)際上,操作系統(tǒng)都會(huì)把虛擬內(nèi)存的高地址部分,用作操作系統(tǒng),低地址部分留給用戶程序使用;


  2. Linux 系統(tǒng)中,高地址的 1GB 空間是操作系統(tǒng)使用;Windows 系統(tǒng)中,高地址的 2GB 的空間被操作系統(tǒng)使用,但是可以調(diào)整;


但是,實(shí)際的物理內(nèi)存只有1GB(假設(shè)值),那么操作系統(tǒng)就要使用自己的騰挪大法,讓用戶程序認(rèn)為4GB的內(nèi)存空間全部可用。


就好比變戲法一樣:十個(gè)碗,九個(gè)蓋,誰(shuí)能玩的溜、不露餡,誰(shuí)就是高手!


計(jì)算一下映射表本身所占據(jù)的空間大?。?


映射表中的每一個(gè)表項(xiàng),指向一個(gè)物理頁(yè)的開(kāi)始地址。


在32位系統(tǒng)中,地址的長(zhǎng)度是4個(gè)字節(jié),那么映射表中的每一個(gè)表項(xiàng)就是占用4個(gè)字節(jié)。


既然需要讓4GB的虛擬內(nèi)存全部可用,那么映射表中就需要能夠表示這所有的4GB空間,那么就一共需要1048576 (4GB / 4KB)個(gè)表項(xiàng)。


所以,映射表占據(jù)的總空間大小就是:1048576 * 4 = 4 MB 的大小。


也就是說(shuō),映射表自己本身,就要占用 1024 個(gè)物理頁(yè)(4MB / 4KB)。


正是因?yàn)槭褂靡粋€(gè)映射表,需要占用這么大的物理內(nèi)存空間,所以才有后面的多級(jí)分頁(yè)機(jī)制。


Linux從頭學(xué)14:【分頁(yè)機(jī)制】-看了這篇文章還沒(méi)徹底搞懂?我自罰三杯!虛擬內(nèi)存看上去被虛線“分割”成4KB的單元,其實(shí)并不是分割,虛擬內(nèi)存仍然是連續(xù)的。


這個(gè)虛線的單元僅僅表示它與映射表中每一個(gè)表項(xiàng)的映射關(guān)系,并最終映射到相同大小的一個(gè)物理內(nèi)存頁(yè)上。


例如:


  1. 虛擬內(nèi)存的 0 ~ 4KB 空間,對(duì)應(yīng)映射表第 0 個(gè)表項(xiàng)中,其中存儲(chǔ)的物理地址是 0x3FFF_F000(最后一個(gè)物理頁(yè));


  2. 虛擬內(nèi)存的 4KB ~ 8KB 空間,對(duì)應(yīng)映射表第 1 個(gè)表項(xiàng)中,其中存儲(chǔ)的物理地址是 0x0000_0000(第 0 個(gè)物理頁(yè));


  3. 虛擬內(nèi)存的最后 4KB 空間,對(duì)應(yīng)映射表最后一個(gè)表項(xiàng)中,其中存儲(chǔ)的物理地址是 0x0000_1000(第 1 個(gè)物理頁(yè));


也就是說(shuō):


虛擬內(nèi)存與映射表之間,是平行的一一對(duì)應(yīng)關(guān)系;


映射表中的物理地址,與物理內(nèi)存之間,是隨機(jī)的映射關(guān)系,哪里可用就指向哪里(物理頁(yè))。


以上就是用一個(gè)映射表,把物理內(nèi)存以4KB為一個(gè)頁(yè)進(jìn)行分配,然后再與虛擬內(nèi)存對(duì)應(yīng)起來(lái),包裝成連續(xù)的虛擬內(nèi)存給用戶使用。


雖然最終使用的物理內(nèi)存是離散的,但是與虛擬內(nèi)存對(duì)應(yīng)的線性地址是連續(xù)的


處理器在訪問(wèn)數(shù)據(jù)、獲取指令時(shí),使用的都是線性地址,只要它是連續(xù)的就可以了,最終都能夠通過(guò)映射表找到實(shí)際的物理地址。


為了有一個(gè)更加感性的認(rèn)識(shí),我們?cè)賮?lái)看一個(gè)稍微具象一點(diǎn)的實(shí)例。


一個(gè)線性地址的尋址過(guò)程

我們假設(shè)用戶程序中有一個(gè)代碼段,那么在這個(gè)程序的LDT(局部描述符表)中,段描述的結(jié)構(gòu)如下:


Linux從頭學(xué)14:【分頁(yè)機(jī)制】-看了這篇文章還沒(méi)徹底搞懂?我自罰三杯!假設(shè)條件如下:


  1. 虛擬內(nèi)存(32位系統(tǒng)):4GB,實(shí)際的物理內(nèi)存 1GB;


  2. 代碼段的開(kāi)始地址位于 3 GB 的地方,也就是 0xC000_0000;


  3. 代碼段的長(zhǎng)度是 1 MB;


我們的目標(biāo)是:查找線性地址0xC000_2020所對(duì)應(yīng)的物理地址。


根據(jù)描述符的結(jié)構(gòu),其中的段基地址是0xC000_0000,界限是0x00100,段描述符中,其它的字段暫時(shí)不用關(guān)心。


界限一共有 20 位,假設(shè)粒度是 4KB,那么 1 MB 的長(zhǎng)度除以 4KB,結(jié)果就是 0x00100。


代碼段的開(kāi)始地址(線性地址)0xC000_0000,位于虛擬內(nèi)存靠近高端四分之一的位置,那么映射表中對(duì)應(yīng)的表項(xiàng),也是位于高端的四分之一的位置。


映射表中每一個(gè)表項(xiàng)指向一個(gè)4KB大小的物理頁(yè),那么長(zhǎng)度為1MB的代碼段,就需要256個(gè)表項(xiàng)。


也就是說(shuō)映射表中有256個(gè)表項(xiàng),指向256個(gè)物理頁(yè):


Linux從頭學(xué)14:【分頁(yè)機(jī)制】-看了這篇文章還沒(méi)徹底搞懂?我自罰三杯!對(duì)于我們要查找的線性地址0xC000_2020,首先把它拆解成兩部分:


高 20 位 0xC0002: 是映射表索引;


低 12 位 0x020: 是物理頁(yè)內(nèi)的偏移地址;


索引值0xC002,對(duì)應(yīng)于下圖中從3GB開(kāi)始的第2個(gè)表項(xiàng):


Linux從頭學(xué)14:【分頁(yè)機(jī)制】-看了這篇文章還沒(méi)徹底搞懂?我自罰三杯!在上面這個(gè)示意圖中,代碼段的開(kāi)始地址0xC000_0000,對(duì)應(yīng)于映射表中索引為0xC0000這個(gè)表項(xiàng),這個(gè)表項(xiàng)中記錄的物理內(nèi)存頁(yè)開(kāi)始地址是0x1000_0000(距離開(kāi)始地址256 MB)。


代碼段的長(zhǎng)度是1 MB,一共需要256個(gè)表項(xiàng),那么最后這個(gè)表項(xiàng)的索引就應(yīng)該是0xC00FF。


那么對(duì)于我們要尋找的線性地址0xC000_2020,對(duì)應(yīng)的表項(xiàng)索引號(hào)是0xC0002,這個(gè)表項(xiàng)中記錄的物理內(nèi)存頁(yè)的開(kāi)始地址是0x2000_0000(距離開(kāi)始地址512 MB)。


找到了物理內(nèi)存的起始地址,再加上偏移量0x020,那么最終的物理地址就是:0x2000_0020。


以上就是通過(guò)映射表,從線性地址到物理地址的頁(yè)轉(zhuǎn)換過(guò)程。


對(duì)于使用二級(jí)頁(yè)表的轉(zhuǎn)換機(jī)制來(lái)說(shuō),原理都是一樣的。無(wú)非是把高20位的索引拆開(kāi)(10 位 10 位),使用兩個(gè)表來(lái)轉(zhuǎn)換,這個(gè)問(wèn)題下一篇文章會(huì)詳細(xì)聊。



------ End ------
本文描述了:通過(guò)一個(gè)映射表,把連續(xù)的虛擬內(nèi)存,映射到離散的物理頁(yè),極大的利用了物理內(nèi)存。


當(dāng)操作系統(tǒng)需要分配一大塊、連續(xù)的內(nèi)存空間給用戶程序時(shí),映射表中的表項(xiàng)可以指向多個(gè)不連續(xù)的物理頁(yè),反正用戶程序接觸不到這一層(用戶程序只與虛擬內(nèi)存交互)。


這樣利用物理內(nèi)存的效率就極大的提高了。


再加上換出和換入機(jī)制(把硬盤(pán)當(dāng)做物理內(nèi)存來(lái)用),讓用戶程序以為有用不完的物理內(nèi)存。


同時(shí),我們也討論了這個(gè)單一映射表的壞處,那就是映射表本身也占用了4MB的物理內(nèi)存空間。


為了解決這個(gè)問(wèn)題,偉大的先驅(qū)者們又引入了多級(jí)映射表(頁(yè)目錄表和頁(yè)表),我們下一篇文章再見(jiàn)!


如果這篇文章對(duì)您有小小的幫助,請(qǐng)是轉(zhuǎn)發(fā)給身邊的小伙伴,讓我們一起進(jìn)步!



本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉
關(guān)閉