文件映射 — 零拷贝读取
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/stat.h>
int fd = open("large.bin", O_RDONLY);
struct stat sb;
fstat(fd, &sb);
// 文件映射到内存 → 像访问数组一样访问文件
char *data = (char *)mmap(nullptr, sb.st_size,
PROT_READ, MAP_PRIVATE, fd, 0);
// 访问 data[0..size-1] 就像读内存,内核负责页缺失加载
munmap(data, sb.st_size);
close(fd);
mmap vs read 的性能
场景: 读取 1GB 文件,顺序访问前半部分
read + 用户缓冲区: 内核 → 用户空间拷贝 1 次
mmap: 内核页缓存直接映射,0 次拷贝
随机访问时 mmap 优势更大: read 每次都进内核,mmap 命中页缓存 = 纯内存访问
匿名映射 — 大块内存分配
// 比 malloc 更适合分配 1GB+ 大块内存
size_t size = 1ULL << 30; // 1GB
void *mem = mmap(nullptr, size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
// munmap 释放 → 立即归还内核,不像 free 可能留着不还
共享内存 IPC
// 进程 A — 创建共享内存
int fd = shm_open("/myshm", O_CREAT | O_RDWR, 0666);
ftruncate(fd, 4096);
int *data = (int *)mmap(nullptr, 4096,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
data[0] = 42; // 写入
munmap(data, 4096);
// 进程 B — 读取
int fd = shm_open("/myshm", O_RDONLY, 0666);
int *data = (int *)mmap(nullptr, 4096,
PROT_READ, MAP_SHARED, fd, 0);
std::cout << data[0]; // 42
munmap(data, 4096);
注意事项
// ⚠️ mmap 不是免费的
// 页故障 (page fault) 有开销 — 第一次访问触发内核分配物理页
// SIGBUS — 文件被截断后继续访问映射区 → 信号杀死进程
// 文件大小必须固定 — mmap 后 ftruncate 扩展文件是 UB