广州公安局门户网站/中国今日新闻
mmap
是 Linux 中用于内存映射的系统调用,允许将文件或设备直接映射到进程的地址空间,从而实现高效的文件访问或进程间通信。以下是对其概念和使用方案的详细说明:
1. 核心概念
- 内存映射:将文件内容直接关联到进程的虚拟内存空间,使得文件操作如同内存读写,避免频繁的
read/write
系统调用。 - 优势:减少数据拷贝、支持随机访问、便于共享内存。
- 场景:大文件处理、进程间通信、高效I/O操作。
2. 函数原型
#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);
3. 参数详解
addr
: 建议的映射起始地址,通常设为NULL
(由内核选择)。length
: 映射区域的长度。prot
: 内存保护模式(按位或组合):PROT_READ
(可读)PROT_WRITE
(可写)PROT_EXEC
(可执行)PROT_NONE
(不可访问)
flags
: 映射类型和属性(常用值):MAP_SHARED
:修改同步到文件,多进程共享。MAP_PRIVATE
:写时复制,修改不写入文件。MAP_ANONYMOUS
:匿名映射(不依赖文件,用于进程间共享内存)。
fd
: 文件描述符(匿名映射时设为-1
)。offset
: 文件中的偏移量(通常为0
)。
4. 使用步骤
- 打开文件:获取文件描述符
fd
。 - 获取文件信息:如通过
fstat
获取文件大小。 - 调用
mmap
:创建内存映射,获得指向映射区域的指针。 - 操作内存:通过指针读写数据(如操作数组)。
- 解除映射:使用
munmap
释放内存。 - 关闭文件:关闭文件描述符。
5. 示例代码
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main() {// 1. 打开文件int fd = open("example.txt", O_RDWR | O_CREAT, 0666);if (fd == -1) {perror("open");exit(EXIT_FAILURE);}// 2. 调整文件大小(确保足够大)ftruncate(fd, 4096); // 扩展为 4KB// 3. 创建内存映射void *addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (addr == MAP_FAILED) {perror("mmap");close(fd);exit(EXIT_FAILURE);}// 4. 操作映射内存sprintf((char *)addr, "Hello from mmap!");printf("File content: %s\n", (char *)addr);// 5. 解除映射并清理if (munmap(addr, 4096) == -1) {perror("munmap");}close(fd);return 0;
}
6. 注意事项
- 文件大小与映射长度:若映射长度超出文件大小,访问超出部分会触发
SIGBUS
。需提前用ftruncate
调整文件大小。 - 权限匹配:
prot
参数需与文件打开模式兼容(如只读文件不可写)。 - 同步数据:
MAP_SHARED
修改会由内核异步写回文件,立即同步需调用msync
。 - 错误处理:检查
mmap
返回值是否为MAP_FAILED
,处理errno
。 - 信号处理:非法访问可能触发
SIGSEGV
(段错误)或SIGBUS
(总线错误)。 - 匿名映射:使用
MAP_ANONYMOUS
和fd = -1
创建进程间共享内存。
7. 常见用途
- 高效文件I/O:处理大文件时减少拷贝开销。
- 进程间通信 (IPC):共享内存通过
MAP_SHARED
映射同一文件。 - 内存分配:替代
malloc
进行大块内存分配(如glibc
的malloc
实现)。
正确使用 mmap
可显著提升性能,但需谨慎处理边界条件和错误,确保程序健壮性。