內存映射
內存映射,簡而言之就是將用戶空間的一段內存區域映射到內核空間,映射成功後,用戶對這段內存區域的修改可以直接反映到內核空間,同樣,內核空間對這段區域的修改也直接反映用戶空間。那麼對於內核空間<---->用戶空間兩者之間需要大量數據傳輸等操作的話效率是非常高的。
因爲mmap系統調用使得進程之間通過映射同一個普通文件實現共享內存。普通文件被映射到進程地址空間後,進程可以像訪問普通內存一樣對文件進行訪問,不必再調用read(),write()等操作。
映射需要包含頭文件 #include<sys/mman.h>
映射函數 void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
接觸映射函數 int munmap(void *addr, size_t length);
參數代表的意義
第一個參數void *addr:指定被映射到進程地址空間的起始地址,一般指定爲NULL,表示讓內核自己選擇。
第二個參數size_t length:需要映射的大小(字節)。
第三個參數int prot:數據的訪問權限,一般PROT_READ|PROT_WRITE表示可讀寫。
第四個參數int flags:一般指定爲MAP_SHARED
第五個參數int fd:映射的文件描述符
第六個參數off_t offset:從文件的什麼位置開始映射,一般指定爲0。
下面我來寫一個映射的程序:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/mman.h>
void sys_err(char *s)
{
perror(s);
exit(1);
}
int main(int argc,char** argv)
{
//判斷傳入的參數個數是否大於等於2
if(argc < 2)
{
printf("usage: mmap1 filename\n");
return 1;
}
//創建一個fd用來接收文件描述符,即第二個參數,也是要被操作的文件
int fd;
fd = open(argv[1],O_RDWR);//argv[1]就是第二個參數
if(fd < 0)
{
sys_err("open");
}
//獲得文件長度
off_t len;
len = lseek(fd,0,SEEK_END);
//將文件映射到當前進程,mem代表映射後內存的首地址
void* mem = mem = mmap(NULL,len,PROT_WRITE,MAP_SHARED,fd,0);
//#define MAP_FAILED ((void*)-1)
if(mem == MAP_FAILED)
{
sys_err("mmap");
}
//關閉文件描述
close(fd);
//用映射後的地址輸出文件內容
printf("%s\n",mem);
//通過映射來修改文件
*(char*)mem = 'N';
*(char*)(mem + 1) = 'I';
((char*)mem)[2]='H';
((char*)mem)[3]='A';
//解除映射
if(-1 == munmap(mem,len))
{
sys_err("munmap");
}
return 0;
}
執行結果爲:
成功的通過映射對文件進行修改!
注意:
mmap並不分配空間, 只是將文件映射到調用進程的地址空間裏(但是會佔掉你的 virutal memory)