mmap读大文件比fread快得多,因其绕过内核缓冲区拷贝,将文件直接映射到进程虚拟内存,实现纯内存操作,避免系统调用与态切换开销,在GB级数据场景下性能提升2–5倍。
为什么 mmap 读大文件比 fread 快得多
mmap 的核心优势在于绕过内核缓冲区拷贝:它把文件直接映射进进程虚拟内存,后续读写变成纯内存操作,没有 read()/write() 系统调用开销,也不触发用户态/内核态频繁切换。对 GB 级日志、数据库页、影像数据等顺序或随机访问场景,性能提升常达 2–5 倍。
但注意:mmap 不是万能加速器——小文件(msync(),否则脏页由内核异步刷盘,崩溃可能丢数据。
Linux 下用 mmap 读取只读大文件的最小可靠写法
关键不是“怎么映射”,而是“怎么避免 SIGBUS 和段错误”。常见错误是忽略文件大小与映射长度对齐、未检查 mmap() 返回值、忘记 munmap()。
-
open()必须带O_RDONLY(读)或O_RDWR(读写),不能用O_APPEND -
lseek()+lstat()获取真实文件大小,传给mmap()的length参数;不能硬写 2GB 或用SIZE_MAX -
mmap()成功返回非MAP_FAILED指针后,**必须用memset()或首次访问前 touch 一页**,防止首次读触发缺页异常被信号中断(尤其在多线程环境) - 映射后按需用
memcpy()或指针偏移访问,无需循环read()
int fd = open("data.bin", O_RDONLY);
struct stat st;
fstat(fd, &st);
void* addr = mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (addr == MAP_FAILED) { /* handle error */ }
// 安全起见,触碰第一页
volatile char dummy = *(char*)addr;
// … 使用 addr 作只读访问
munmap(addr, st.st_size);
close(fd);
写入大文件时,MAP_SHARED + msync 的正确节奏
写操作比读敏感得多:用 MAP_PRIVATE 写的是 copy-on-write 页,不会落盘;必须用 MAP_SHARED 才能同步回文件。但直接狂写再 msync() 会阻塞太久,影响响应。
立即学习“C++免费学习笔记(深入)”;