閱讀「深入理解作業系統」的虛擬儲存器一章做個筆記。
在早期的操作計算機作業系統中,操作主存是CPU直接訪問的實體地址。後面演進為通過VA(vatual address)來管理訪問,這樣做幾個好處:
- 將主存(就是我們說的記憶體條)看作是磁碟的一快取記憶體
- 為每個程式提供一致的訪問空間,簡化應用程式
- 每個程式獨立的空間而不被其它程式破壞
下面這張從wiki上摘取的,從這張圖可以看出VM遮蔽了處理了細節,給上層一個統一的,連續的地址空間。
cpu通過虛擬地址怎樣訪問到主存資料的呢?如下圖,先把虛擬地址(va)翻譯成實體地址(pa),這個工作是由MMU(memory management unit)完成,它是cpu晶片上的專用硬體,但是這個工作要和OS緊密配合才能完成,因為要在OS管理的Page Table來動態查詢並翻譯虛擬地址。後面會講到詳細的翻譯過程。
頁,頁表?
頁(page)是怎麼來的?虛擬記憶體的本質設計思路就是把記憶體當作磁碟的快取記憶體,每個程式都是獨立的地址空間,可以分配2**64(64位作業系統)大小的虛擬空間,但是這些資料並不是長期駐留在記憶體中的,如果記憶體緊張時,某個活動的程式需求記憶體但是未分配快取時,會犧牲其它某個程式的記憶體,把這些當前閒置的記憶體資料交換出(swapping或者paging)到磁碟上。當被交換出的資料在下次需求的時候,又從磁碟換入到記憶體中。這時不難理解,程式執行的過程中記憶體資料是有換入換出的,那麼效能問題就會顯現出來了。大家都知道讀寫磁碟資料的開銷在哪裡,就是尋道定位(特別是之前的旋轉磁碟)讀取第一個位元組資料。所以就會以塊為單位進行讀取,可以理解成批量的意思,就是page。那頁表(page table)又是什麼呢?可以把頁表理解成一個hasmap結構的資料體,key值就是虛擬地址,而value儲存的資訊是該虛擬地址當前的動態資訊,包括是否進行分配,還是分配了但資料在磁碟上,或者資料已在記憶體上。這樣MMU就可以結合這個頁表資料把虛擬地址翻譯成實體地址。可以檢視前面wiki的那張圖理解。
fork對記憶體操作
fork就是建立一個新的程式,子程式也會把父程式的地址空間全部複製一份過來。但是使用的是COW(copy on write)技術,只有有寫操作時,當前被影響的記憶體頁才會複製,只讀的時候其實實體記憶體上的資料還是隻有一份。可以思考下redis的RDB持久方式,就是通過fork一個子程式來同時進行save操作,如果在save的整個過程中資料沒有寫變,那麼其實不會佔用double的記憶體的。
mmap是什麼?
我的淺顯理解就是把一個fd(檔案描述符,一般就是通過open函式打的一個本地磁碟本地檔案)對映到當前程式的一段虛擬地址空間中,這樣我們可以像操作記憶體一樣操作檔案。這樣可以用來進行程式的記憶體共享通訊,因為兩個程式可以對映同一個檔案,然後各自操作相應的虛擬地址空間。