mmap 比 fread 适合读大文件,因其按需映射、避免大块内存分配和冗余拷贝,尤其适用于只读或稀疏访问的 gb 级文件;但全量顺序读时可能因缺页中断变慢,此时 read + 预读更优。

为什么 mmap 比 fread 适合读大文件
因为 mmap 不把整个文件一次性拷贝进用户内存,而是让内核按需把磁盘页映射到进程地址空间。你访问哪段,内核才加载哪段,避免了 malloc + fread 的大块内存分配和冗余拷贝。尤其对 GB 级日志、数据库快照、二进制数据集这类只读或稀疏访问的场景,延迟更低、系统开销更小。
但注意:mmap 不是万能加速器——如果文件远大于物理内存,且你顺序扫全量内容,mmap 反而可能因频繁缺页中断拖慢速度;这时候 read(2) 配合预读(posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED))更稳。
mmap 最简安全用法(Linux / macOS)
核心就三步:打开文件 → 获取大小 → 映射。关键不是“怎么写”,而是“怎么避错”:
-
open()必须带O_RDONLY(只读)或O_RDWR(可写),不能用O_APPEND或O_TRUNC - 映射前务必用
fstat()拿真实文件大小,别信lseek(fd, 0, SEEK_END)—— 对某些特殊文件(如设备节点、/proc 下文件)会失败或返回 0 -
mmap()返回MAP_FAILED时,必须检查errno:EINVAL(offset 未按页对齐)、ENOMEM(虚拟地址空间不足,不是内存不够)、EPERM(文件不可执行且noexec挂载选项启用) - 映射后记得
munmap(),否则泄漏的是虚拟内存(不是物理内存),但会耗尽进程地址空间(尤其在 32 位或受限容器里)
示例片段:
立即学习“C++免费学习笔记(深入)”;
NetShop软件特点介绍: 1、使用ASP.Net(c#)2.0、多层结构开发 2、前台设计不采用任何.NET内置控件读取数据,完全标签化模板处理,加快读取速度3、安全的数据添加删除读取操作,利用存储过程模式彻底防制SQL注入式攻击4、前台架构DIV+CSS兼容IE6,IE7,FF等,有利于搜索引挚收录5、后台内置强大的功能,整合多家网店系统的功能,加以优化。6、支持三种类型的数据库:Acces
int fd = open("data.bin", O_RDONLY);
struct stat st;
fstat(fd, &st);
void* ptr = mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (ptr == MAP_FAILED) { /* 处理 errno */ }
// 使用 ptr 当作普通指针读取
munmap(ptr, st.st_size);
close(fd);
Windows 上没 mmap 怎么办
Windows 没原生 mmap,但有语义等价的 CreateFileMapping + MapViewOfFile。别硬套 Linux 写法,重点差异在:
- 文件句柄必须用
GENERIC_READ打开,且CreateFileMapping的flProtect要匹配:只读用PAGE_READONLY,可写用PAGE_READWRITE - 映射大小不能超过文件实际长度,且
MapViewOfFile的dwNumberOfBytesToMap若为 0,表示映射全部(Linux 下mmap的length为 0 是非法的) - 错误判断靠
GetLastError(),常见ERROR_MAPPED_FILE(文件被其他进程以不兼容方式打开)、ERROR_NOT_ENOUGH_MEMORY(不是物理内存不足,而是用户模式地址空间碎片化)
跨平台代码建议封装一层,比如用宏区分:#ifdef _WIN32 走 Windows API,否则走 mmap。
映射后访问越界或 SIGBUS 怎么办
SIGBUS 是 mmap 最典型的运行时错误,根本原因是访问了未映射的地址——不是空指针那种崩溃,而是内核直接发信号终止进程。常见原因:
- 文件在映射后被截断(
ftruncate)或删除(unlink),导致后续访问对应页时缺页失败 - 映射时用了
MAP_SHARED,但文件被其他进程并发修改,破坏了页对齐假设 - 用
sizeof(struct)计算结构体数组偏移,但结构体有 padding,跨页边界时部分字段落在未映射区域 - 忘了
st.st_size是字节数,却当成“元素个数”去循环访问(比如for (int i=0; i<size i arr>,但 <code>arr是uint64_t*)
调试技巧:用 gdb 捕获 SIGBUS,然后 info proc mappings 看当前映射范围;生产环境建议加 sigaction 捕获并记录 si_addr(出错地址)与 /proc/self/maps 对比。
真正麻烦的不是映射本身,是文件生命周期和内存访问模式的耦合——一旦文件被外部工具轮转、压缩或清空,mmap 区域就变成定时炸弹。









