記憶體對映檔案完全攻略(原理和效能)

2020-07-16 10:04:38
假設採用標準系統呼叫 open()、read() 和 write() 來順序讀取磁碟檔案,每個檔案存取都需要系統呼叫和磁碟存取。又或者採用虛擬記憶體技術,以將檔案 I/O 作為常規記憶體存取,這種方法稱為記憶體對映檔案,允許一部分虛擬記憶體與檔案進行邏輯關聯,這會導致顯著的效能提高。

基本機制

實現檔案的記憶體對映是將每個磁碟塊對映到一個或多個記憶體頁面。

最初,檔案存取按普通請求調頁來進行,從而產生缺頁錯誤。這樣,檔案的頁面大小部分從檔案系統讀取到物理頁面(有些系統可以選擇一次讀取多個頁面大小的資料塊)。以後,檔案的讀寫就按常規記憶體存取來處理。通過記憶體的檔案操作,沒有採用系統呼叫 read() 和 write() 的開銷,而且簡化了檔案的存取和使用。

請注意,記憶體對映檔案的寫入不一定是對磁碟檔案的即時(同步)寫入。有的作業系統定期檢查檔案的記憶體對映頁面是否已被修改,以便選擇是否更新到物理檔案。當關閉檔案時,所有記憶體對映的資料會寫到磁碟,並從進程虛擬記憶體中刪除。

有些作業系統僅通過特定的系統呼叫來提供記憶體對映,而通過標準的系統呼叫來處理所有其他檔案 I/O。然而,有的系統不管檔案是否指定為記憶體對映,都選擇對檔案進行記憶體對映。

以 Solaris 為例,如果一個檔案指定為記憶體對映(採用系統呼叫 mmaP()),那麼 Solaris 會將該檔案對映到進程地址空間。如果一個檔案通過普通系統呼叫,如 open()、read() 和 write() 來開啟和存取,那麼 Solaris 仍然採用記憶體對映檔案。然而,這個檔案是對映到核心地址空間,無論檔案如何開啟,Solaris 都將所有檔案 I/O 視為記憶體對映的,以允許檔案存取在高效的記憶體子系統中進行。

多個進程可以允許並行地記憶體對映同一檔案,以便允許資料共用。任何一個進程的寫入會修改虛擬記憶體的資料,並且其他對映同一檔案部分的進程都可看到。

根據虛擬記憶體的相關知識,可以清楚地看到記憶體對映部分的共用是如何實現的:每個共用進程的虛擬記憶體對映指向實體記憶體的同一頁面,而該頁面有磁碟塊的複製,這種記憶體共用如圖 1 所示。

內存映射文件
圖 1 記憶體對映檔案