每天花5分鐘,瞭解linux內存相關的知識點

剛開始學習c語言的時候,會接觸到一個概念,就是虛擬內存,當時真的是一頭霧水,根本不知道什麼是虛擬內存,我為此感到好無奈,隨著對c語言的深入理解,慢慢的,我開始明白了虛擬內存的概念,今天我就講講我對虛擬內存的理解,鄙人如有哪裡不對的,請指正。

虛擬內存的由來

我們知道cpu的速度非常快,外設相對於cpu又很慢,這時就需要一箇中介來緩解這種差異,這個中介是誰呢?那就是我們常說的內存。

現代的操作系統都是多任務的,那麼多個任務同時工作,就會有內存訪問的衝突,那麼如何解決這種衝突呢?虛擬內存就是解決這種衝突的。

假設有兩個進程1和2,操作系統給進程1和2進程一種假象,操作系統告訴1和2,我的整個內存都是你的,你們隨便用,管飽,而事實上,操作系統讓他們隨便用的只是虛擬內存,當1和2開始使用內存的時候,系統才根據他們的虛擬地址為他們分配物理內存,也就是說,是動態分配的。

進程1和2認為他們使用的虛擬地址就是物理地址,但是事實上,linux內核為他們的虛擬地址做了一個轉換,轉換成了物理地址。

那麼虛擬內存是如何與物理內存進行轉換的呢?

linux內核的做法是,利用頁目錄表進行的映射。

Linux 虛擬地址與物理地址之間的映射

每天花5分鐘,瞭解linux內存相關的知識點

圖1

上圖中的VA代表虛擬地址,PA代表物理地址,通過上圖我們知道,我們的程序將虛擬地址傳遞給CPU,CPU會根據MMU將虛擬地址進行映射,也就是虛擬地址通過MMU部件後,輸出的結果就是PA,也就是物理地址。

MMU 是根據什麼機制映射的物理地址呢?

MMU是根據頁目錄表和頁表進行虛擬地址與物理地址的映射的,我們只要把虛擬地址告訴MMU,MMU會主動去查頁目錄表以及頁表,最終找到所需要的物理地址。

MMU它也不是神仙,知道我們的頁目錄表存在內存的什麼位置,所以MMU並不會直接去內存查找頁目錄,而是通過寄存器CR3來知道頁目錄的基地址,換句話說,頁目錄的基地址存在了CR3的寄存器中,MMU讀取CR3的寄存器就知道了頁目錄的基地址,是不是覺得明白了許多。

具體的映射關係如下所示:

每天花5分鐘,瞭解linux內存相關的知識點

圖2

上圖就是虛擬地址到物理地址的映射過程。

線性地址你可以認為是虛擬地址就行,因為現在的linux內存模型基本上是平坦模型,也就是段的基地址從0開始,所以虛擬地址和線性地址是相等的關係。

下面我就根據上圖,來詳細說明映射的過程:

1. 首先將線性地址分成三份,這三份分別佔用了 22-31位,12-21位,0-11 位。

22-31 位表示的是頁目錄的索引,頁目錄你可以認為就是一個數組,這個索引代表數組的索引,MMU會根據這個索引,來選取頁目錄數組的哪個數組元素。

12-21 位表示的是頁表的索引,頁表也可以認為是一個數組,MMU會根據這個索引,來選取頁表數組中的哪個數組元素。

0-11 位表示的頁面的偏移,當MMU通過頁目錄表和頁表知道了頁面的基地址後,會用頁面的基地址 加上 頁面的偏移來算出真正的物理地址。

2. MMU 去讀取CR3的寄存器的值,獲取頁目錄的基地址。

3. 獲取完頁目錄的基地址後,會根據線性地址中的22-31位的值,來獲取頁目錄的索引,即為pgd_offset,然後通過基地址加上 4*pgd_offset 後,獲取到了頁目錄項。為什麼乘以4呢?是因為 頁目錄數組中的元素佔用4個字節,所以 用 4*pgd_offset 才能獲取到頁目錄項。

4. 獲取完頁目錄項後,我們就知道了頁表的基地址,因為頁目錄項中存放的是頁表的基地址,虛擬地址中的12-21 位表示的是頁表的索引,我們設為pg_offset ,然後,通過頁表的基地址 加上 4*pg_offset 後,就得出了頁面的物理地址。這裡乘以4,也是因為頁表項佔用4個字節。

5. 我們得出了頁面的物理地址,已經成功了一大半了,最後根據虛擬地址中的0-11 位得到頁面的偏移,即為p_offset,然後通過頁面的物理地址加上 p_offset後,形成了最終的物理地址。

以上就是虛擬地址到物理地址之間的映射流程,是不是感覺對虛擬地址有了進一步的理解了。

可能有的人會問,是誰往CR3寄存器了存的頁目錄的基地址?每個進程它的頁目錄表一樣嗎?預知後事,請聽下回分解,請大家對我進行關注,讓我覺得寫的東西對有些人是有幫助的,謝謝。

請大家關注我哦

每天花5分鐘,瞭解linux內存相關的知識點

圖3


分享到:


相關文章: