linux記憶體對映mmap原理分析

2021-09-10 01:32:32 字數 4148 閱讀 8526

個人分類: linux核心設計與實現

記憶體對映,簡而言之就是將使用者空間的一段記憶體區域對映到核心空間,對映成功後,使用者對這段記憶體區域的修改可以直接反映到核心空間,同樣,核心空間對這段區域的修改也直接反映使用者空間。那麼對於核心空間使用者空間兩者之間需要大量資料傳輸等操作的話效率是非常高的。

以下是乙個把普遍檔案對映到使用者空間的記憶體區域的示意圖。

圖一:

二、基本函式

mmap函式是unix/linux下的系統呼叫,詳細內容可參考《unix netword programming》卷二12.2節。

mmap系統呼叫並不是完全為了用於共享記憶體而設計的。它本身提供了不同於一般對普通檔案的訪問方式,程序可以像讀寫記憶體一樣對普通檔案的操作。而posix或系統v的共享記憶體ipc則純粹用於共享目的,當然mmap()實現共享記憶體也是其主要應用之一。

mmap系統呼叫使得程序之間通過對映同乙個普通檔案實現共享記憶體。普通檔案被對映到程序位址空間後,程序可以像訪問普通記憶體一樣對檔案進行訪問,不必再呼叫read(),write()等操作。mmap並不分配空間, 只是將檔案對映到呼叫程序的位址空間裡(但是會佔掉你的 virutal memory), 然後你就可以用memcpy等操作寫檔案, 而不用write()了.寫完後,記憶體中的內容並不會立即更新到檔案中,而是有一段時間的延遲,你可以呼叫msync()來顯式同步一下, 這樣你所寫的內容就能立即儲存到檔案裡了.這點應該和驅動相關。 不過通過mmap來寫檔案這種方式沒辦法增加檔案的長度, 因為要對映的長度在呼叫mmap()的時候就決定了.如果想取消記憶體對映,可以呼叫munmap()來取消記憶體對映

[cpp]view plain

copy

void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)

mmap用於把檔案對映到記憶體空間中,簡單說mmap就是把乙個檔案的內容在記憶體裡面做乙個映像。對映成功後,使用者對這段記憶體區域的修改可以直接反映到核心空間,同樣,核心空間對這段區域的修改也直接反映使用者空間。那麼對於核心空間使用者空間兩者之間需要大量資料傳輸等操作的話效率是非常高的。

首先,「對映」這個詞,就和數學課上說的「一一對映」是乙個意思,就是建立一種一一對應關係,在這裡主要是只 硬碟上檔案 的位置與程序 邏輯位址空間 中一塊大小相同的區域之間的一一對應,如圖1中過程1所示。這種對應關係純屬是邏輯上的概念,物理上是不存在的,原因是程序的邏輯位址空間本身就是不存在的。在記憶體對映的過程中,並沒有實際的資料拷貝,檔案沒有被載入記憶體,只是邏輯上被放入了記憶體,具體到**,就是建立並初始化了相關的資料結構(struct address_space),這個過程有系統呼叫mmap()實現,所以建立記憶體對映的效率很高。

圖1.記憶體對映原理  

既然建立記憶體對映沒有進行實際的資料拷貝,那麼程序又怎麼能最終直接通過記憶體操作訪問到硬碟上的檔案呢?那就要看記憶體對映之後的幾個相關的過程了。

mmap()會返回乙個指標ptr,它指向程序邏輯位址空間中的乙個位址,這樣以後,程序無需再呼叫read或write對檔案進行讀寫,而只需要通過ptr就能夠操作檔案。但是ptr所指向的是乙個邏輯位址,要操作其中的資料,必須通過mmu將邏輯位址轉換成實體地址,如圖1中過程2所示。這個過程與記憶體對映無關。

前面講過,建立記憶體對映並沒有實際拷貝資料,這時,mmu在位址對映表中是無法找到與ptr相對應的實體地址的,也就是mmu失敗,將產生乙個缺頁中斷,缺頁中斷的中斷響應函式會在swap中尋找相對應的頁面,如果找不到(也就是該檔案從來沒有被讀入記憶體的情況),則會通過mmap()建立的對映關係,從硬碟上將檔案讀取到物理記憶體中,如圖1中過程3所示。這個過程與記憶體對映無關。

如果在拷貝資料時,發現物理記憶體不夠用,則會通過虛擬記憶體機制(swap)將暫時不用的物理頁面交換到硬碟上,如圖1中過程4所示。這個過程也與記憶體對映無關。

從**層面上看,從硬碟上將檔案讀入記憶體,都要經過檔案系統進行資料拷貝,並且資料拷貝操作是由檔案系統和硬體驅動實現的,理論上來說,拷貝資料的效率是一樣的。但是通過記憶體對映的方法訪問硬碟上的檔案,效率要比read和write系統呼叫高,這是為什麼呢?原因是read()是系統呼叫,其中進行了資料拷貝,它首先將檔案內容從硬碟拷貝到核心空間的乙個緩衝區,如圖2中過程1,然後再將這些資料拷貝到使用者空間,如圖2中過程2,在這個過程中,實際上完成了 兩次資料拷貝 ;而mmap()也是系統呼叫,如前所述,mmap()中沒有進行資料拷貝,真正的資料拷貝是在缺頁中斷處理時進行的,由於mmap()將檔案直接對映到使用者空間,所以中斷處理函式根據這個對映關係,直接將檔案從硬碟拷貝到使用者空間,只進行了 一次資料拷貝 。因此,記憶體對映的效率要比read/write效率高。

圖2.read系統呼叫原理

下面這個程式,通過read和mmap兩種方法分別對硬碟上乙個名為「mmap_test」的檔案進行操作,檔案中存有10000個整數,程式兩次使用不同的方法將它們讀出,加1,再寫回硬碟。通過對比可以看出,read消耗的時間將近是mmap的兩到三倍。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define max 10000

int main()

int i=0;

int count=0, fd=0;

struct timeval tv1, tv2;

int *array = (int *)malloc( sizeof(int)*max );

/*read*/

gettimeofday( &tv1, null );

fd = open( "mmap_test", o_rdwr );

if( sizeof(int)*max != read( fd, (void *)array, sizeof(int)*max ) )

printf( "reading data failed.../n" );

return -1;

for( i=0; i++array[ i ];

if( sizeof(int)*max != write( fd, (void *)array, sizeof(int)*max ) )

printf( "writing data failed.../n" );

return -1;

free( array );

close( fd );

gettimeofday( &tv2, null );

printf( "time of read/write: %dms/n", tv2.tv_usec-tv1.tv_usec );

/*mmap*/

gettimeofday( &tv1, null );

fd = open( "mmap_test", o_rdwr );

array = mmap( null, sizeof(int)*max, prot_read|prot_write, map_shared, fd, 0 );

for( i=0; i++array[ i ];

munmap( array, sizeof(int)*max );

msync( array, sizeof(int)*max, ms_sync );

free( array );

close( fd );

gettimeofday( &tv2, null );

printf( "time of mmap: %dms/n", tv2.tv_usec-tv1.tv_usec );

return 0;

輸出結果:

time of read/write: 154ms

time of mmap: 68ms

mmap記憶體對映原理

mmap概念 mmap是一種記憶體對映檔案的方法,即將乙個檔案或者其它物件對映到程序的位址空間,實現檔案磁碟位址和程序虛擬位址空間中一段虛擬位址的一一對映關係。特點 實現這樣的對映關係後,程序就可以採用指標的方式讀寫操作這一段記憶體,而系統會自動回寫髒頁面到對應的檔案磁碟上,即完成了對檔案的操作而不...

mmap記憶體對映原理

mmap記憶體對映的實現過程,總的來說可以分為三個階段 一 程序啟動對映過程,並在虛擬位址空間中為對映建立虛擬對映區域 1 程序在使用者空間呼叫庫函式mmap,原型 void mmap void start,size t length,int prot,int flags,int fd,off t ...

linux記憶體對映mmap原理分析

一直都對記憶體對映檔案這個概念很模糊,不知道它和虛擬記憶體有什麼區別,而且對映這個詞也很讓人迷茫,今天終於搞清楚了。下面,我先解釋一下我對對映這個詞的理解,再區分一下幾個容易混淆的概念,之後,什麼是記憶體對映就很明朗了。首先,對映 這個詞,就和數學課上說的 一一對映 是乙個意思,就是建立一種一一對應...