mmap函数介绍

本文深入探讨了Unix/Linux环境下mmap函数的应用,解释了其如何通过映射文件到进程地址空间来提高文件访问速度,特别适用于频繁访问文件并进行指针移动的情况。详细阐述了mmap函数的参数及其功能,包括映射文件到内存、设置访问权限和映射位置。并通过实例展示了如何使用mmap优化文件访问效率。
 mmap函数是unix/linux下的系统调用,来看《Unix Netword programming》卷二12.2节对mmap的介绍:
The mmap function maps either a file or a Posix shared memory object into the address space of a process.We use this function for three purposes:
1. with a regular file to provide memory-mapped I/O
2. with special files to provide anonymous memory mappings
3. with shm_open to provide Posix shared memory between unrelated processes

         mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。
         mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。

         我们的程序中大量运用了mmap,用到的正是mmap的这种“像访问普通内存一样对文件进行访问”的功能。实践证明,当要对一个文件频繁的进行访问,并且指针来回移动时,调用mmap比用常规的方法快很多。
         来看看mmap的定义:
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);

         参数fd为即将映射到进程空间的文件描述字,一般由open()返回,同时,fd可以指定为-1,此时须指定flags参数中的MAP_ANON,表明进行的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然只能用于具有亲缘关系的进程间通信)。

         len是映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起。

         prot参数指定共享内存的访问权限。可取如下几个值的或:PROT_READ(可读),PROT_WRITE(可写),PROT_EXEC(可执行),PROT_NONE(不可访问)。

         flags由以下几个常值指定:MAP_SHARED, MAP_PRIVATE, MAP_FIXED。其中,MAP_SHARED,MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用。
         如果指定为MAP_SHARED,则对映射的内存所做的修改同样影响到文件。如果是MAP_PRIVATE,则对映射的内存所做的修改仅对该进程可见,对文件没有影响。

         offset参数一般设为0,表示从文件头开始映射。

         参数addr指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成。函数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。

         看看下面这个图(来自《Unix Netword programming》卷二12.2节),对mmap进一步加深印象:

         这里不再详细介绍mmap的参数,读者可参考mmap手册页或者《Unix Netword programming》卷二12.2节获得进一步的信息。
         最后,举个例子来结束本节。4.2节说过,Fileinformation数组是以二进制的形式写进一个叫inforindex的文件中。那么,当要访问Fileinformation数组时,代码类似这样:
struct stat st;
char buffer=” inforindex”;
Fileinformation *_fileinfoIndexptr = NULL;
if(stat(buffer,&st)<0)
{
       fprintf(stderr,"error to stat %s\n",buffer);
       exit(-1);
}
// mmap the inforindex to _fileinfoIndexptr
int fd=open(buffer, O_RDONLY);
if(fd<0)
{
       printf("error to open %s\n",buffer);
       exit(-1);
}
_fileinfoIndexptr   = (Fileinformation*)mmap(NULL,st.st_size, PROT_READ,MAP_SHARED,fd,0);

if(MAP_FAILED == _fileinfoIndexptr)
{
       printf("error to mmap %s\n",buffer);
close(fd);
       exit(-1);
}
close(fd);
 
 
mmap 是 POSIX 系统(例如 Unix、Linux)上的一个函数,它提供了一种将文件映射到内存的方法,允许程序像访问内存一样来访问文件内容,常用于提高文件访问效率,特别是对于大文件操作 [^4]。 mmap 函数原型为:`void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);` ,其输入参数介绍如下 [^1][^3][^4][^5]: - **addr**:指定映射的起始地址,通常设为 `NULL`,由内核来分配,映射成功后返回该地址。 - **length**:代表将文件中映射到内存的部分的长度,单位为字节数,一般要求为页大小整数倍。 - **prot**:映射区域的保护方式,可以为以下几种方式的组合: - `PROT_EXEC`:映射区域可被执行。 - `PROT_READ`:映射区域可被读取。 - `PROT_WRITE`:映射区域可被写入。 - `PROT_NONE`:映射区域不能存取。 - **flags**:影响映射区域的各种特性,在调用 `mmap()` 时必须要指定 `MAP_SHARED` 或 `MAP_PRIVATE` : - `MAP_FIXED`:如果参数 `start` 所指的地址无法成功建立映射时,则放弃映射,不对地址做修正,通常不鼓励使用。 - `MAP_SHARED`:对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。 - `MAP_PRIVATE`:对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write),对此区域作的任何修改都不会写回原来的文件内容。 - **fd**:要映射到内存中的文件描述符,即调用 `mmap` 前调用 `open` 函数的返回值。如果使用匿名内存映射时,即 `flags` 中设置了 `MAP_ANONYMOUS`,`fd` 设为 -1。 - **offset**:文件映射的偏移量,通常设置为 0,代表从文件最前方开始对应,`offset` 必须是分页大小的整数倍。 此外,使用 `mmap` 映射内存必须是页面大小的整数倍,面向流的设备不能进行 `mmap`,其实现和硬件有关。操作完成后,可使用 `munmap` 函数来解除映射,函数原型为:`int munmap(void *addr, size_t length);` [^1][^2]。 ### 示例代码 ```c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> int main() { int fd; char *map; struct stat sb; // 打开文件 fd = open("example.txt", O_RDONLY); if (fd == -1) { perror("open"); return 1; } // 获取文件大小 if (fstat(fd, &sb) == -1) { perror("fstat"); close(fd); return 1; } // 进行内存映射 map = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (map == MAP_FAILED) { perror("mmap"); close(fd); return 1; } // 输出映射内容 printf("%s", map); // 解除映射 if (munmap(map, sb.st_size) == -1) { perror("munmap"); } // 关闭文件 close(fd); return 0; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值