mmap記憶體對映

2021-09-07 11:28:34 字數 2172 閱讀 9889

記憶體對映是個很有用,也很有意思的思想。我們都知道作業系統分為使用者態和核心態,使用者態是不能直接和物理裝置打交道的,如果想把硬碟的一塊區域讀到使用者態,則需要兩次拷貝(硬碟->核心->使用者),但是記憶體對映的設計只需要發生一次的拷貝,大大的提高了讀取資料的效率。那麼記憶體對映的原理和核心是如何實現的呢?

因為記憶體對映涉及到虛擬記憶體的管理,虛擬記憶體到物理記憶體的對映,因此在詳細介紹記憶體對映前先普及(回憶)一下相關的概念。

目前cpu架構主要分為三種:smp, numa, mpp,詳細的介紹參考cpu架構。這裡主要關注mmu和tlb在cpu中的角色和位置。 

上圖是intel的i7處理器乙個核的架構圖,圖中可以看出每乙個cpu核都已乙個自己的mmu和tlb。

關於linux程序和執行緒的話題想必大家都不陌生,這也是面試時候經常被問到的問題,後續我會專門寫一篇博文介紹linux執行緒和程序的區別,已經核心是如何實現的。這裡我們只需要知道下面幾個概念即可: 

* 作業系統本身也是乙個程序 

* 作業系統核心層面沒有執行緒的概念,只有程序的概念,因此執行緒在核心看來也是乙個程序,只是比較特殊 

* 執行緒的實現是glibc實現的(pthread),包括建立,管理等

虛擬位址是面向程序的一套虛擬記憶體的位址,為了更好的管理記憶體,並且能夠保證記憶體對程式設計師而言是透明的,也就是寫程式的時候對每乙個程式來說都是一樣的位址空間,因此提出了虛擬記憶體的概念,對應的就是虛擬位址。這裡我們不關注具體的細節,為了後面的講解,我們簡單的了解一下虛擬記憶體在核心層面是怎麼進行管理的。 

這張圖右側的程序虛擬器對於每乙個程序都是一樣的,就是上面說的虛擬空間,然後對於程序,核心對每乙個程序都維護了乙個task_struch的結構,其中有三個重要的成員,pgd指向改程序的頁表首位址,然後mmap和mm_rb都是用來管理vm的結構,vm是虛擬記憶體管理的基本單元,含有記憶體的型別,起始和結束位址,mmap是線性表實現的,mm_rb則使用紅黑樹進行管理,分別適用不同的場景。

mmu(memory management unit),記憶體管理單元,主要負責cpu記憶體訪問的時候將虛擬位址轉換為實體地址的單元。也就是說cpu想要訪問記憶體必須先經過mmu的轉換,獲得真正的實體地址,才能讀寫物理記憶體的資料。其實mmu只是乙個簡單的計算單元,它通過虛擬位址查詢頁表,找到對應的實體地址,然後返回給cpu。在查詢頁表的過程中可能發生多次的物理記憶體訪問,這取決於系統採用頁表管理系統是幾級的,目前linux的頁表是四級的,因此需要查詢四次頁表,每一次查詢都會獲得乙個實體地址指向下一級頁表的記憶體位址,知道最後獲得實際要訪問的記憶體實體地址。 

從圖中可以看出,當cpu得到乙個虛擬位址去訪問記憶體的時候會先將虛擬位址傳送到mmu(1),然後mmu會先從tlb查詢是否存在這個虛擬位址到實體地址的快取,如果存在則直接返回給cpu,如果沒有則會根據虛擬位址講過計算獲得物理記憶體中頁表項的位址然後讀取得到pte(linux可能要讀取四次),pte就是物理記憶體位址或者硬碟儲存位址。然後mmu會將該pte快取在tlb中,最後使用這個實體地址再次訪問物理記憶體或者硬碟位址獲得要訪問的內容。

基礎知識介紹完畢,那麼到底什麼是記憶體對映呢,對映讓我們不禁都會想起數學上的對映關係,是的就是那個意思,這裡是講裝置或者硬碟儲存的一塊空間對映到物理記憶體,然後操作這塊物理記憶體就是在操作實際的硬碟空間,不需要經過核心態傳遞。比如你的硬碟上有乙個檔案,你可以使用linux系統提供的mmap介面,講這個檔案對映到程序一塊虛擬位址空間,這塊空間會對應一塊物理記憶體,當你讀寫這塊物理空間的時候,就是在讀取實際的磁碟檔案,就是這麼直接,這麼高效。通常諸如共享庫的載入都是通過記憶體對映的方式載入到物理記憶體的。

mmap本身其實是乙個很簡單的操作,在程序的頁表中新增乙個頁表項,該頁表項是物理記憶體的位址。呼叫mmap的時候,核心會在改程序的虛擬空間的對映區域查詢一塊滿足需求的空間用於對映該檔案,然後生成該虛擬位址的頁表項,改頁表項此時的有效位(標誌是否已經在物理記憶體中)為0,頁表項的內容是檔案的磁碟位址,此時mmap的任務已經完成。 

當mmap建立完頁表的對映後,就可以操作改塊記憶體了,進行的所有改動都會自動寫會磁碟檔案。第一次訪問該塊記憶體的時候,因為頁表項的有效位還是0,就會發生缺頁中斷,然後cpu會使用該頁表項的內容也就是磁碟的檔案位址,講該位址指向的內容載入到物理記憶體,並需改頁表項的內容為該實體地址,有效位置為1. 

有對映必然有解除對映,系統提供了乙個munmap的介面去解除指定位址的對映關係。munmap主要的功能是清除頁表項,解除這個對映關係,但是這個過程中會涉及到快取的重新整理,虛擬記憶體vm的刪除,tlb的一致性(tlb shootdown操作),這裡就不再詳細講解。

記憶體對映/

mmap記憶體對映

記憶體對映是個很有用,也很有意思的思想。我們都知道作業系統分為使用者態和核心態,使用者態是不能直接和物理裝置打交道的,如果想把硬碟的一塊區域讀到使用者態,則需要兩次拷貝 硬碟 核心 使用者 但是記憶體對映的設計只需要發生一次的拷貝,大大的提高了讀取資料的效率。那麼記憶體對映的原理和核心是如何實現的呢...

記憶體對映mmap

應用與裝置驅動之間資料互動,很多時候都使用copy to user與copy from user。但如果在追求高效能的驅動上,這種拷貝顯然不是最佳的做法。linux核心提供了一種記憶體對映的機制,它主要完成將裝置的位址空間對映到使用者空間或者直接使用使用者空間中的位址,這樣做的目的顯然是為了提公升系...

Linux記憶體對映 mmap

linux提供了記憶體對映函式mmap,它把檔案內容對映到一段記憶體上 準確說是虛擬記憶體上 通過對這段記憶體的讀取和修改,實現對檔案的讀取和修改,先來看一下mmap的函式宣告 原型 void mmap void addr,size t length,int prot,int flags,int f...