Linux 內存管理 - 詳解 mmap 原理
- 一句話概括 mmap
mmap 的作用,在應用這一層,是讓你把文件的某一段,當作內存一樣來訪問。將文件映射到物理內存,將進程虛擬空間映射到那塊內存。
這樣,進程不僅能像訪問內存一樣讀寫文件,多個進程映射同一文件,還能保證虛擬空間映射到同一塊物理內存,達到內存共享的作用。
- 虛擬內存?虛擬空間?
其實是一個概念,前一篇對於這個詞沒有確切的定義,現在定義一下:
虛擬空間就是進程看到的所有地址組成的空間,虛擬空間是某個進程對分配給它的所有物理地址(已經分配的和將會分配的)的重新映射。
而虛擬內存,爲啥叫虛擬內存,是因爲它就不是真正的內存,是假的,因爲它是由地址組成的空間,所以在這裏,使用虛擬空間這個詞更加確切和易懂。(不過虛擬內存這個詞也不算錯)
2.1 虛擬空間原理
2.1.1 物理內存
首先,物理地址實際上也不是連續的,通常是包含作爲主存的 DRAM 和 IO 寄存器
以前的 CPU(如 X86)是爲 IO 劃分單獨的地址空間,所以不能用直接訪問內存的方式(如指針)IO,只能用專門的方法(in/read/out/write)諸如此類。
現在的 CPU 利用 PCI 總線將 IO 寄存器映射到物理內存,所以出現了基於內存訪問的 IO。
還有一點補充的,就如同進程空間有一塊內核空間一樣,物理內存也會有極小一部分是不能訪問的,爲內核所用。
2.1.2 三個總線
這裏再補充下三個總線的知識,即:地址總線、數據總線、控制總線
-
地址總線,用來傳輸地址
-
數據總線,用來傳輸數據
-
控制總線,用來傳輸命令
比如 CPU 通過控制總線發送讀取命令,同時用地址總線發送要讀取的數據虛地址,經過 MMU 後到內存
內存通過數據總線將數據傳輸給 CPU。
虛擬地址的空間和指令集的地址長度有關,不一定和物理地址長度一致,比如現在的 64 位處理器,從 VA 角度看來,可以訪問 64 位的地址,但地址總線長度只有 48 位,所以你可以訪問一個位於 2^52 這個位置的地址。
2.1.3 虛擬內存地址轉換(虛地址轉實地址)
上面已經明確了虛擬內存是虛擬空間,即地址的集合這一概念。基於此,來說說原理。
如果還記得操作系統課程裏面提到的虛地址,那麼這個虛地址就是虛擬空間的地址了,虛地址通過轉換得到實地址,轉換方式課程內也講得很清楚,虛地址頭部包含了頁號(段地址和段大小,看存儲模式:頁存儲、段存儲,段頁式),剩下部分是偏移量,經過 MMU 轉換成實地址。
存儲方式
如圖則是頁式存儲動態地址變換的方式
虛擬地址頭部爲頁號通過查詢頁表得到物理頁號,假設一頁時 1K,那麼頁號 * 偏移量就得到物理地址
如圖所示,段式存儲
虛擬地址頭部爲段號,段表中找到段基地址加上偏移量得到實地址
段頁式結合兩者,如圖所示。
- mmap 映射
至此,如果對虛擬空間已經瞭解了,那麼接下來,作爲 coder,應該自動把虛擬空間無視掉,因爲 Linux 的目的也是要讓更多額進程能享用內存,又不讓進程做麻煩的事情,是將虛擬空間和 MMU 都透明化,讓進程(和 coder)只需要管對內存怎樣使用。
所以現在開始不再強調虛擬空間了。
mmap 就是將文件映射到內存上,進程直接對內存進行讀寫,然後就會反映到磁盤上。
-
虛擬空間獲取到一段連續的地址
-
在沒有讀寫的時候,這個地址指向不存在的地方(所以,上圖中起始地址和終止地址是還沒分配給 進程的)
-
好了,根據偏移量,進程要讀文件數據了,數據佔在兩個頁當中(物理內存着色部分)
-
這時,進程開始使用內存了,所以 OS 給這兩個頁分配了內存(即缺頁異常)(其餘部分還是沒有分配)
-
然後剛分配的頁內是空的,所以再將相同偏移量的文件數據拷貝到物理內存對應頁上。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/nVqt_j1K4NUENRmqQ1NbFQ