日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

从C++中的const到MMU(存储器管理单元)(MMU部分为网页整理)

發(fā)布時(shí)間:2025/7/14 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从C++中的const到MMU(存储器管理单元)(MMU部分为网页整理) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

? ?先來(lái)回顧一段小代碼:

#include <iostream> using namespace std; int main() {char *s = "Hello World!";printf("%s\n",s);s[0] = 'B';printf("%s\n",s);return 0; }

用G++編譯 : g++ test1.cpp

之后顯示:

對(duì)的,沒(méi)有報(bào)錯(cuò),編譯器的英文是說(shuō),這是一個(gè)過(guò)時(shí)的寫(xiě)法。

不管他,我們來(lái)運(yùn)行一下,畢竟只是警告!

看見(jiàn)結(jié)果了吧,Bus erro: 10. 說(shuō)明后面一個(gè)printf出現(xiàn)了異常。下面是查找到的Bus Error錯(cuò)誤解釋:

在《C專(zhuān)家編程》中提到了總線錯(cuò)誤bus error(core dumped)。

總線錯(cuò)誤幾乎都是由于未對(duì)齊的讀或?qū)懸鸬摹?/p>

它之所以稱(chēng)為總線錯(cuò)誤,是因?yàn)槌霈F(xiàn)未對(duì)齊的內(nèi)存訪問(wèn)請(qǐng)求時(shí),被堵塞的組件就是地址總線。對(duì)齊的意思就是數(shù)據(jù)項(xiàng)只能存儲(chǔ)在地址是數(shù)據(jù)項(xiàng)大小的整倍數(shù)的內(nèi)存位置上。

現(xiàn)代的計(jì)算機(jī)架構(gòu)中,尤其是RISC架構(gòu),都需要字對(duì)齊,因?yàn)榕c任意的對(duì)齊有關(guān)的額外邏輯都會(huì)使內(nèi)存系統(tǒng)更大且更慢。

通過(guò)迫使每個(gè)內(nèi)存訪問(wèn)局限在一個(gè)cache行或者一個(gè)單獨(dú)的頁(yè)面內(nèi),可以極大地簡(jiǎn)化(并加速)如cache控制器和內(nèi)存管理單元這樣的硬件。

頁(yè)和cache的大小都是經(jīng)過(guò)精心設(shè)計(jì)的,這樣只要遵守對(duì)齊規(guī)則就可以保證一個(gè)原子數(shù)據(jù)項(xiàng)不會(huì)跨過(guò)一個(gè)頁(yè)或cache塊的邊界。

本地變量放在堆棧里,new出來(lái)的變量放在堆里面,全局變量放在全局?jǐn)?shù)據(jù)區(qū)里面,而全局變量里的常量是放在代碼段里的,且會(huì)被默認(rèn)為const,放在代碼段內(nèi),而代碼段是不寫(xiě)的。



好了下面為了更便于理解,先簡(jiǎn)單介紹下MMU(Memory Manage Unit),內(nèi)存管理單元。MMU有一個(gè)內(nèi)存保護(hù)作用,其中代碼段是不可寫(xiě)的,要是寫(xiě)了,內(nèi)不會(huì)產(chǎn)生一個(gè)check,所以產(chǎn)生了Bus Error。


但是為什么沒(méi)有報(bào)錯(cuò)呢,因?yàn)槲覀凃_過(guò)了編譯器。編譯到s[0] = 'B'時(shí),它不知道s是否為const。


正確的作法可在前面加一個(gè)const 。


那么考慮另外一段程序。

#include <iostream> using namespace std; int main() {char s[] = "Hello World!";printf("%s\n",s);s[0] = 'B';printf("%s\n",s);return 0; }

用G++編譯,沒(méi)有報(bào)錯(cuò)。OK,運(yùn)行:

為什么這里沒(méi)有錯(cuò)誤呢?

通常我們認(rèn)為s[]是一個(gè)數(shù)組,數(shù)組是位于堆棧內(nèi)的。堆棧里有很大一塊空間,用來(lái)放Hello world!,這里的賦值號(hào)“=”是拷貝的意思 。這個(gè)s[0]的賦值是可以的。好了 ,如果你還沒(méi)弄懂,繼續(xù)看下面一段代碼。

#include <iostream> using namespace std; int main() {const char *s1 = "Hello World!";//默認(rèn)為const,在代碼段內(nèi),不可寫(xiě)。計(jì)算機(jī)里面有一個(gè)MMU,內(nèi)存管理單元。char s2[] = "Hello World!";printf("s1's address is %p\n",s1);printf("s2's address is %p\n",s2);printf("main's address is %p\n",main);//MMU,負(fù)責(zé)內(nèi)存保護(hù),//cout<<s<<endl; // s[0] = 'B'; // cout<<s<<endl;return 0; }

用32位編譯:g++ test.cpp -m32后 顯示如下:

? ?


OK我們發(fā)現(xiàn) s1,main的位于低地址區(qū)域,而s2位于高地址區(qū)域。s1,main在全局區(qū),而s2位于堆棧內(nèi)。

PS:教大家一個(gè)口訣,const在*前,則修飾的是對(duì)象,const在*后,則修飾的是指針。


接下來(lái)深入理解內(nèi)存管理單元MMU(以下內(nèi)容整理自某博客):

MMU的主要作用就是把虛擬地址轉(zhuǎn)換成物理地址。一個(gè)32位的CPU,它的地址范圍是0~0xFFFFFFFF (4G)而對(duì)于一個(gè)64位的CPU,它的地址范圍為0~0xFFFFFFFFFFFFFFFF (64T),這個(gè)范圍就是我們的程序能夠產(chǎn)生的地址范圍,我們把這個(gè)地址范圍稱(chēng)為虛擬地址空間,該空間中的某一個(gè)地址我們稱(chēng)之為虛擬地址。與虛擬地址空間和虛擬地址相對(duì)應(yīng)的則是物理地址空間和物理地址,大多數(shù)時(shí)候我們的系統(tǒng)所具備的物理地址空間只是虛擬地址空間的一個(gè)子集,這里舉一個(gè)最簡(jiǎn)單的例子直觀地說(shuō)明這兩者,對(duì)于一臺(tái)內(nèi)存為256MB的32bit x86主機(jī)來(lái)說(shuō),它的虛擬地址空間范圍是0~0xFFFFFFFF(4G),而物理地址空間范圍是0x000000000~0x0FFFFFFF(256MB)。在沒(méi)有使用虛擬存儲(chǔ)器的機(jī)器上,虛擬地址被直接送到內(nèi)存總線上,使具有相同地址的物理存儲(chǔ)器被讀寫(xiě)。而在使用了虛擬存儲(chǔ)器的情況下,虛擬地址不是被直接送到內(nèi)存地址總線上,而是送到內(nèi)存管理單元——MMU。

大多數(shù)使用虛擬存儲(chǔ)器的系統(tǒng)都使用一種稱(chēng)為分頁(yè)(paging)。虛擬地址空間劃分成稱(chēng)為頁(yè)(page)的單位,而相應(yīng)的物理地址空間也被進(jìn)行劃分,單位是頁(yè)框().頁(yè)和頁(yè)框的大小必須相同。接下來(lái)配合圖片我以一個(gè)例子說(shuō)明頁(yè)與頁(yè)框之間在MMU的調(diào)度下是如何進(jìn)行映射的:




在這個(gè)例子中我們有一臺(tái)可以生成16位地址的機(jī)器,它的虛擬地址范圍從0x0000~0xFFFF(64K),而這臺(tái)機(jī)器只有32K的物理地址,因此他可以運(yùn)行64K的程序,但該程序不能一次性調(diào)入內(nèi)存運(yùn)行。這臺(tái)機(jī)器必須有一個(gè)達(dá)到可以存放64K程序的外部存儲(chǔ)器(例如磁盤(pán)或是FLASH)以保證程序片段在需要時(shí)可以被調(diào)用。在這個(gè)例子中,頁(yè)的大小為4K,頁(yè)框大小與頁(yè)相同(這點(diǎn)是必須保證的,內(nèi)存和外圍存儲(chǔ)器之間的傳輸總是以頁(yè)為單位的),對(duì)應(yīng)64K的虛擬地址和32K的物理存儲(chǔ)器,他們分別包含了16個(gè)頁(yè)和8個(gè)頁(yè)框。


? ? ?我們先根據(jù)上圖解釋一下分頁(yè)后要用到的幾個(gè)術(shù)語(yǔ),在上面我們已經(jīng)接觸了頁(yè)和頁(yè)框,上圖中綠色部分是物理空間,其中每一格表示一個(gè)物理頁(yè)框。橘×××部分是虛擬空間,每一格表示一個(gè)頁(yè),它由兩部分組成,分別是 Index(頁(yè)框索引)和位p(present 存在位), Index的意義很明顯,它指出本頁(yè)是往哪個(gè)物理頁(yè)框進(jìn)行映射的,位p的意義則是指出本頁(yè)的映射是否有效,如上圖,當(dāng)某個(gè)頁(yè)并沒(méi)有被映射時(shí)(或稱(chēng)映射無(wú)效, Index部分為X),該位為0,映射有效則該位為1。


? ?我們執(zhí)行下面這些指令(本例子的指令不針對(duì)任何特定機(jī)型,都是偽指令)
例1:
? ?MOVE REG,0 //將0號(hào)地址的值傳遞進(jìn)寄存器REG.
? ?虛擬地址0將被送往MMU,MMU看到該虛地址落在頁(yè)0范圍內(nèi)(頁(yè)0范圍是0到4095),從上圖我們看到頁(yè)0所對(duì)應(yīng)(映射)的頁(yè)框?yàn)?(頁(yè)框2的地址范圍是8192到12287),因此MMU將該虛擬地址轉(zhuǎn)化為物理地址8192,并把地址8192送到地址總線上。內(nèi)存對(duì)MMU的映射一無(wú)所知,它只看到一個(gè)對(duì)地址8192的讀請(qǐng)求并執(zhí)行它。MMU從而把0到4096的虛擬地址映射到8192到12287的物理地址。


例2:
? ?MOVE REG,8192
? ?被轉(zhuǎn)換為
? ?MOVE REG,24576
? ?因?yàn)樘摂M地址8192在頁(yè)2中,而頁(yè)2被映射到頁(yè)框6(物理地址從24576到28671)


例3:
? ?MOVE REG,20500
? ?被轉(zhuǎn)換為
? ?MOVE REG,12308
? ?虛擬地址20500在虛頁(yè)5(虛擬地址范圍是20480到24575)距開(kāi)頭20個(gè)字節(jié)處,虛頁(yè)5映射到頁(yè)框3(頁(yè)框3的地址范圍是 12288到16383),于是被映射到物理地址12288+20=12308。


? ? ?通過(guò)適當(dāng)?shù)脑O(shè)置MMU,可以把16個(gè)虛頁(yè)隱射到8個(gè)頁(yè)框中的任何一個(gè),但是這個(gè)方法并沒(méi)有有效的解決虛擬地址空間比物理地址空間大的問(wèn)題。從上圖中我們可以看到,我們只有8個(gè)頁(yè)框(物理地址),但我們有16個(gè)頁(yè)(虛擬地址),所以我們只能把16個(gè)頁(yè)中的8個(gè)進(jìn)行有效的映射。我們看看例4會(huì)發(fā)生什么情況

? ? ?MOV REG,32780
? ? ?虛擬地址32780落在頁(yè)8的范圍內(nèi),從上圖總我們看到頁(yè)8沒(méi)有被有效的進(jìn)行映射(該頁(yè)被打上X),這是又會(huì)發(fā)生什么?MMU注意到這個(gè)頁(yè)沒(méi)有被映射,于是通知CPU發(fā)生一個(gè)缺頁(yè)故障(page fault).這種情況下操作系統(tǒng)必須處理這個(gè)頁(yè)故障,它必須從8個(gè)物理頁(yè)框中找到1個(gè)當(dāng)前很少被使用的頁(yè)框并把該頁(yè)框的內(nèi)容寫(xiě)入外圍存儲(chǔ)器(這個(gè)動(dòng)作被稱(chēng)為page copy),隨后把需要引用的頁(yè)(例4中是頁(yè)8)映射到剛才釋放的頁(yè)框中(這個(gè)動(dòng)作稱(chēng)為修改映射關(guān)系),然后從新執(zhí)行產(chǎn)生故障的指令(MOV REG,32780)。假設(shè)操作系統(tǒng)決定釋放頁(yè)框1,那么它將把虛頁(yè)8裝入物理地址的4-8K,并做兩處修改:首先把標(biāo)記虛頁(yè)1未被映射(原來(lái)虛頁(yè)1是被影射到頁(yè)框1的),以使以后任何對(duì)虛擬地址4K到8K的訪問(wèn)都引起頁(yè)故障而使操作系統(tǒng)做出適當(dāng)?shù)膭?dòng)作(這個(gè)動(dòng)作正是我們現(xiàn)在在討論的),其次他把虛頁(yè)8對(duì)應(yīng)的頁(yè)框號(hào)由X變?yōu)?,因此重新執(zhí)行MOV REG,32780時(shí),MMU將把32780映射為4108。


? ? ?我們大致了解了MMU在我們的機(jī)器中扮演了什么角色以及它基本的工作內(nèi)容是什么,下面我們將舉例子說(shuō)明它究竟是如何工作的(注意,本例中的MMU并無(wú)針對(duì)某種特定的機(jī)型,它是所有MMU工作的一個(gè)抽象)。


? ? ?首先明確一點(diǎn),MMU的主要工作只有一個(gè),就是把虛擬地址映射到物理地址。
我們已經(jīng)知道,大多數(shù)使用虛擬存儲(chǔ)器的系統(tǒng)都使用一種稱(chēng)為分頁(yè)(paging)的技術(shù),就象我們剛才所舉的例子,虛擬地址空間被分成大小相同的一組頁(yè),每個(gè)頁(yè)有一個(gè)用來(lái)標(biāo)示它的頁(yè)號(hào)(這個(gè)頁(yè)號(hào)一般是它在該組中的索引,這點(diǎn)和C/C++中的數(shù)組相似)。在上面的例子中0~4K的頁(yè)號(hào)為0,4~8K的頁(yè)號(hào)為1,8~12K的頁(yè)號(hào)為2,以此類(lèi)推。而虛擬地址(注意:是一個(gè)確定的地址,不是一個(gè)空間)被MMU分為2個(gè)部分,第一部分是頁(yè)號(hào)索引(page Index),第二部分則是相對(duì)該頁(yè)首地址的偏移量(offset). 。我們還是以剛才那個(gè)16位機(jī)器結(jié)合下圖進(jìn)行一個(gè)實(shí)例說(shuō)明,該實(shí)例中,虛擬地址8196被送進(jìn)MMU,MMU把它映射成物理地址。16位的CPU總共能產(chǎn)生的地址范圍是0~64K,按每頁(yè)4K的大小計(jì)算,該空間必須被分成16個(gè)頁(yè)。而我們的虛擬地址第一部分所能夠表達(dá)的范圍也必須等于16(這樣才能索引到該頁(yè)組中的每一個(gè)頁(yè)),也就是說(shuō)這個(gè)部分至少需要4個(gè)bit。一個(gè)頁(yè)的大小是4K(4096),也就是說(shuō)偏移部分必須使用12個(gè)bit來(lái)表示(2^12=4096,這樣才能訪問(wèn)到一個(gè)頁(yè)中的所有地址),8196的二進(jìn)制碼如下圖所示:



該地址的頁(yè)號(hào)索引為0010(二進(jìn)制碼),既索引的頁(yè)為頁(yè)2,第二部分為000000000100(二進(jìn)制),偏移量為4。頁(yè)2中的頁(yè)框號(hào)為6(頁(yè)2映射在頁(yè)框6,見(jiàn)上圖),我們看到頁(yè)框6的物理地址是24~28K。于是MMU計(jì)算出虛擬地址8196應(yīng)該被映射成物理地址24580(頁(yè)框首地址+偏移量=24576+4=24580)。同樣的,若我們對(duì)虛擬地址1026進(jìn)行讀取,1026的二進(jìn)制碼為0000010000000010,page index="0000"=0,offset=010000000010=1026。頁(yè)號(hào)為0,該頁(yè)映射的頁(yè)框號(hào)為2,頁(yè)框2的物理地址范圍是8192~12287,故MMU將虛擬地址1026映射為物理地址9218(頁(yè)框首地址+偏移量=8192+1026=9218)。以上就是MMU的工作過(guò)程。


轉(zhuǎn)載于:https://blog.51cto.com/feilei/1371443

總結(jié)

以上是生活随笔為你收集整理的从C++中的const到MMU(存储器管理单元)(MMU部分为网页整理)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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