输入关键词开始搜索

mmap — 内存映射与共享内存

文件映射 — 零拷贝读取

#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