c++如何实现基于内存映射(mmap)的文件随机读写优化方案【实战】

风晨君_7162

风晨君_7162

2026-03-24

630人浏览

原创

mmap更快是因为将文件映射到虚拟内存,读写变为指针操作,省去内核缓冲区拷贝和系统调用开销;但仅适用于大文件(>1MB)、随机访问且页面已加载的场景。

c++如何实现基于内存映射(mmap)的文件随机读写优化方案【实战】

为什么 mmap 比普通 read/write 更快?

因为 mmap 把文件直接映射进进程虚拟内存,读写就变成指针操作,绕过了内核缓冲区拷贝和系统调用开销。但前提是:你真在做**随机访问**,且文件够大(通常 > 1MB)、访问跨度大、不频繁触发缺页异常。

常见错误现象:lseek + read 在小块随机读时反复陷入内核,CPU 花在上下文切换上;而 mmap 后用 *(ptr + offset) 直接取数据,快得多——但仅当页面已加载时成立。

  • 不要对小文件(mmap,开销反超 read
  • mmap 不保证立即加载物理页,首次访问仍会触发缺页中断(软缺页),若文件不在 page cache 中,会变硬缺页(慢)
  • 必须配合 madvise(..., MADV_RANDOM) 或 MADV_WILLNEED 提示内核,否则预读逻辑可能拖累随机访问性能

如何安全地用 mmap 实现随机读写(C++)

核心不是“怎么映射”,而是“怎么避免崩溃+数据不丢”。关键在标志位、同步时机和地址对齐。

使用场景:日志索引文件、数据库 WAL、固定格式的二进制数据块(如每条记录 512 字节,需按 ID 随机跳转)。

  • 读写都用 PROT_READ | PROT_WRITE,映射标志必须含 MAP_SHARED(否则修改不落盘)
  • 起始偏移 offset 必须是 sysconf(_SC_PAGE_SIZE) 的整数倍,否则 mmap 失败并返回 MAP_FAILED
  • 写完关键数据后,立刻调用 msync(ptr, len, MS_SYNC),别等进程退出——否则断电可能丢最后几页
  • 避免用 std::vector 包裹 mmap 返回指针,它会在析构时 delete[],导致段错误

示例片段:

int fd = open("data.bin", O_RDWR);
off_t offset = 4096; // 对齐到页
size_t len = 1024 * 1024;
void* ptr = mmap(nullptr, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
if (ptr == MAP_FAILED) { /* handle error */ }
// 安全写入第 3 块(假设每块 512B)
char* block3 = static_cast<char>(ptr) + 2 * 512;
memcpy(block3, new_data, 512);
msync(block3, 512, MS_SYNC); // 只刷这一块,更高效</char>

munmap 后还能访问映射内存吗?

不能。一旦调用 munmap,对应地址空间被回收,再读写就是野指针,行为未定义(多数情况直接 SEGFAULT)。

容易踩的坑:

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
  • 把 mmap 返回的指针存进类成员,但析构里只关 fd 没调 munmap → 内存泄漏 + 程序重启后可能映射失败(地址冲突)
  • 多线程共享同一块映射,一个线程 munmap 后其他线程还在用 → 崩溃无警告
  • 误以为 close(fd) 会自动 munmap → 不会,fd 和映射完全解耦

建议封装成 RAII 类,构造映射,析构强制 munmap,且禁止拷贝(只允许移动)。

Windows 上能用 mmap 吗?

不能直接用 mmap,但可用 CreateFileMapping + MapViewOfFile 实现等价功能。接口不同,语义一致。

跨平台陷阱:

  • Linux 下 mmap 的 offset 是文件内偏移;Windows 的 MapViewOfFile 的 dwFileOffsetHigh/Low 也是文件偏移,但要求 64KB 对齐(而非页对齐),实际仍建议按页对齐以保兼容
  • Linux 用 msync 刷盘;Windows 用 FlushViewOfFile + FlushFileBuffers(后者针对文件句柄,别漏)
  • 错误码体系完全不同:mmap 失败返回 MAP_FAILED;Windows API 返回 NULL,需调 GetLastError()

如果项目必须跨平台,别手写两套,用 boost::interprocess::mapped_file 或封装一层薄抽象——但要注意它默认不启用 MADV_RANDOM 类似提示,需自行 ioctl 或平台特定调用。

最易被忽略的点:mmap 映射区域的生命周期独立于文件描述符,也独立于文件本身是否被删除。rm 掉文件,只要映射还活着,读写照常;但文件被 truncate,再访问超出原大小的部分会触发 SIGBUS。这事发生前毫无征兆。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

2023.09.22

549

3

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

2024.03.01

1698

6

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

2026.04.23

379

31

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

2023.10.19

3188

3

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

2025.10.17

5089

12

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2025.12.29

3829

9

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

2026.01.19

466

15

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

4418

6

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

2025.12.24

1229

20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习