0

0

C++如何通过内存重映射(mremap)实现动态数组的快速无拷贝扩容?(系统编程)

穿越時空

穿越時空

发布时间:2026-02-28 14:16:03

|

295人浏览过

|

来源于php中文网

原创

mremap仅支持mmap(map_anonymous)分配的页对齐内存,因new/malloc内存不满足vma独立性与页对齐要求,调用会失败并设errno=einval。

c++如何通过内存重映射(mremap)实现动态数组的快速无拷贝扩容?(系统编程)

为什么 mremap 不能直接用于普通 newmalloc 分配的内存

因为 mremap 只作用于通过 mmap(且带 M MAP_ANONYMOUS)分配的页对齐内存块。用 newmallocstd::vector 分配的内存由堆管理器维护,其地址不保证页对齐,也不在内核的 VMA(Virtual Memory Area)中独立成区——mremap 会直接返回 MAP_FAILED 并设 errno = EINVAL

实操建议:

  • 必须用 mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) 分配起始内存
  • 分配大小必须是系统页大小(通常为 4096)的整数倍,可用 getpagesize() 获取
  • 后续所有扩容/缩容都只能基于该 mmap 返回的指针,不能混用 freedelete

mremap 扩容失败时最常遇到的三个错误

不是所有扩容都能成功。内核需要在原映射后方“拼接”新页,这依赖虚拟地址空间连续性与权限一致性。

常见错误现象与应对:

立即学习C++免费学习笔记(深入)”;

摩笔天书
摩笔天书

摩笔天书AI绘本创作平台

下载
  • errno == ENOMEM:目标地址空间被占用(如栈、其他 mmap 区域插在中间),此时 mremap 不会自动找空洞,必须手动 mmap 新区域 + memcpy + munmap 原区——已非“无拷贝”
  • errno == EFAULT:传入的旧地址不是有效 mmap 起始地址(比如偏移了几个字节),检查是否直接用了数组下标指针而非原始 mmap 返回值
  • errno == EAGAIN:系统临时无法满足大块连续 VMA(尤其在低内存或碎片化严重时),应退回到传统拷贝扩容路径,不能重试

如何安全地把 mremap 接入类模板(比如仿 std::vector

关键不在扩容逻辑本身,而在生命周期管理和异常安全:C++ 对象构造/析构不能跨 mremap 边界隐式发生。

实操要点:

  • 只用 mremap 管理原始内存(char*std::byte*),对象必须用 placement new 显式构造,销毁时显式调用析构函数
  • 扩容前,需先在新地址范围用 placement new 构造新增元素;缩容时,必须先显式析构被截断的尾部对象,再调 mremap
  • 禁止对含非平凡析构函数的类型(如 std::string)做 MREMAP_MAYMOVE,因移动后旧地址析构会 crash——除非你确保旧地址内容已全部析构完毕

性能和可移植性的真实代价

mremap 的“无拷贝”仅指用户态数据不 memcpy,但内核仍要更新页表项、可能触发 TLB shootdown,在多核高竞争场景下反而比小规模 memcpy 慢。

更现实的限制:

  • Linux 特有,macOS / Windows 完全不支持,无法跨平台抽象
  • glibc 封装的 realloc 绝不会用 mremap 处理 malloc 内存,别指望标准容器自动优化
  • 调试困难:GDB 和 AddressSanitizer 默认不识别 mmap 内存的边界,越界访问可能静默失败或报错位置漂移

真正需要它的地方很少:通常是自研高性能 ring buffer、共享内存池或实时音视频帧缓存——而且得接受它和 RAII、STL 容器天然互斥。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

870

2023.08.02

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

429

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

599

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

429

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

599

2023.08.10

数据库Delete用法
数据库Delete用法

数据库Delete用法:1、删除单条记录;2、删除多条记录;3、删除所有记录;4、删除特定条件的记录。更多关于数据库Delete的内容,大家可以访问下面的文章。

287

2023.11.13

drop和delete的区别
drop和delete的区别

drop和delete的区别:1、功能与用途;2、操作对象;3、可逆性;4、空间释放;5、执行速度与效率;6、与其他命令的交互;7、影响的持久性;8、语法和执行;9、触发器与约束;10、事务处理。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.12.29

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

1314

2023.07.26

Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

0

2026.02.28

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 10.4万人学习

C 教程
C 教程

共75课时 | 5.1万人学习

C++教程
C++教程

共115课时 | 19.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号