對于C/C++程序員來說,內(nèi)存分配再正常不過,C語言中的malloc:
int* a = (int*)malloc(sizeof(int));
C++中的new:
int* a = new int(10);
接下來的問題是變量a占用的內(nèi)存是誰給我們分配的呢?
答案是運行在用戶態(tài)的內(nèi)存分配器,如果你愿意,也可以繞過內(nèi)存分配器自己來管理內(nèi)存。
接下來的問題是a占用的內(nèi)存在哪里呢?
答案是進(jìn)程地址空間中的堆區(qū),堆區(qū)在這里:
內(nèi)存中真的有像圖中這樣的布局嗎?
答案是: 沒有 。
這就是所謂的虛擬內(nèi)存。
既然是虛擬內(nèi)存那么這里的堆區(qū)又是從哪里來的呢?
答案是操作系統(tǒng)。
當(dāng)我們在C/C++中分配內(nèi)存時,內(nèi)存分配器從堆區(qū)中找到可用內(nèi)存,但如果沒有找到則向操作系統(tǒng)申請。
那么操作系統(tǒng)又是從哪里找到的內(nèi)存呢?
答案是:操作系統(tǒng)從物理內(nèi)存中找到一塊可用內(nèi)存分配出去。
問題來了,既然操作系統(tǒng)管理的是物理內(nèi)存,而操作系統(tǒng)分配給進(jìn)程的又是虛擬內(nèi)存,精神分裂啊有沒有,這是怎么一回事呢?
原來這并不沖突,操作系統(tǒng)會為每個進(jìn)程分配一張表,記錄了從虛擬內(nèi)存到物理內(nèi)存的映射,這張表就叫頁表。
因此,盡管操作系統(tǒng)管理的是物理內(nèi)存,但進(jìn)程或者說程序員是看不到物理內(nèi)存的,我們只能看到虛擬內(nèi)存,程序運行時在發(fā)送內(nèi)存讀寫指令時MMU會將虛擬內(nèi)存轉(zhuǎn)換為物理內(nèi)存。
接下來的問題是頁表在哪里?
答案是: 在內(nèi)存中 。
你可以將頁表放在內(nèi)存中的任何位置上,只要能告訴CPU在哪里即可。
誰來負(fù)責(zé)構(gòu)造頁表呢?答案是操作系統(tǒng),操作系統(tǒng)負(fù)責(zé)創(chuàng)建頁表,頁表本質(zhì)上就是一個數(shù)組,處理器規(guī)定頁表的格式,操作系統(tǒng)按照這種格式構(gòu)建好頁表,創(chuàng)建好后即可告訴CPU。
該怎樣告訴CPU呢?
答案是:通過寫特定的寄存器。
CPU中有特定的寄存器,以x86處理器為例,其中的控制寄存器cr3就用來保存頁表的地址,假設(shè)指針pagetable指向頁表,那么可以這樣設(shè)置:
mov $(pagetable), %eax
mov %eax, %cr3
pagetable必須是物理地址,頁表本身就用來將虛擬地址轉(zhuǎn)為物理地址,因此向cr3中寫入虛擬地址是沒有道理的。
接下來的問題是什么時候?qū)㈨摫韺懭隿r3寄存器呢?
答案是:很多時候,操作系統(tǒng)初始化階段、進(jìn)程切換時等。
現(xiàn)在你應(yīng)該知道了吧,其實內(nèi)存管理(段式管理、頁式管理)是處理器提供的一種機(jī)制,操作系統(tǒng)只是這種機(jī)制的使用者,我們常說的虛擬內(nèi)存是處理器本身的一種能力, 如果處理器本身不提供這種能力,那么操作系統(tǒng)自己是很難高效實現(xiàn)虛擬內(nèi)存的 。
CPU才是管理內(nèi)存真正的大boss。
實際上如果你去看類似x86這樣的處理器編程手冊時就會發(fā)現(xiàn),我們在操作系統(tǒng)課中熟悉的很多概念其實是處理器這種硬件提供的,操作系統(tǒng)僅僅是利用這些硬件的一層軟件。
因此,從這個角度看,操作系統(tǒng)僅僅是CPU的一個“驅(qū)動程序”而已。
-
cpu
+關(guān)注
關(guān)注
68文章
10800瀏覽量
210738 -
內(nèi)存
+關(guān)注
關(guān)注
8文章
2962瀏覽量
73802 -
分配器
+關(guān)注
關(guān)注
0文章
193瀏覽量
25691
發(fā)布評論請先 登錄
相關(guān)推薦
評論