如何无需memcpy复制,将多块内存页映射为连续虚拟地址空间?
无需
memcpy()实现内存页连续映射的方案(Windows 用户态) 针对你提出的需求——将多块独立分配的内存页重映射为连续虚拟地址且不复制数据,在Windows用户态下可以通过匿名内存映射Section实现,核心是借助Section对象关联原有内存的物理页,再重新映射为连续地址,具体实现如下:
实现步骤及代码示例
1. 创建匿名内存Section
先创建一个总大小等于三块内存之和的匿名Section,作为物理页的统一容器:
HANDLE hSection = CreateFileMapping( INVALID_HANDLE_VALUE, // 使用分页文件作为后端存储 NULL, PAGE_READWRITE, // 权限需与原有内存保持一致 0, n1 + n2 + n3, NULL // 匿名Section,不命名 ); if (hSection == NULL) { // 处理创建失败逻辑 return; }
2. 将原有内存页关联到Section的对应偏移
使用MapViewOfFileEx将Section的指定区域映射到原有内存的虚拟地址,替换原有映射关系,让原有内存的物理页关联到Section的连续偏移位置:
// 关联p1到Section的起始位置(偏移0) BOOL success = MapViewOfFileEx( hSection, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, n1, p1 // 指定映射到原有p1的地址,覆盖原VirtualAlloc的映射 ); if (!success) { /* 处理错误逻辑 */ } // 关联p2到Section的偏移n1处 success = MapViewOfFileEx( hSection, FILE_MAP_READ | FILE_MAP_WRITE, 0, n1, // Section内的偏移量 n2, p2 ); if (!success) { /* 处理错误逻辑 */ } // 关联p3到Section的偏移n1+n2处 success = MapViewOfFileEx( hSection, FILE_MAP_READ | FILE_MAP_WRITE, 0, n1 + n2, n3, p3 ); if (!success) { /* 处理错误逻辑 */ }
3. 映射Section为连续虚拟地址
现在将整个Section映射到一个新的连续虚拟地址,即可得到拼接后的内存空间:
char* pAll = (char*)MapViewOfFile( hSection, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, n1 + n2 + n3 ); if (pAll == NULL) { /* 处理错误逻辑 */ }
此时pAll就是连续的虚拟地址,pAll对应原p1的内容,pAll+n1对应原p2,pAll+n1+n2对应原p3,完全无需memcpy复制数据。
4. 资源清理
当不再需要原有内存的映射时,解除映射;最后释放Section资源:
// 解除原有p1/p2/p3的映射 UnmapViewOfFile(p1); UnmapViewOfFile(p2); UnmapViewOfFile(p3); // 解除pAll的映射并关闭Section句柄 UnmapViewOfFile(pAll); CloseHandle(hSection);
关键注意事项
- 所有内存的保护属性必须完全一致(例如均为
PAGE_READWRITE),否则无法关联到同一个Section。 - 原有内存必须是通过
VirtualAlloc分配的可修改映射的虚拟内存,栈内存或静态分配内存无法使用此方法。 - 实际代码中必须添加完整的错误检查,避免因句柄无效、权限不足等问题导致崩溃。
内容的提问来源于stack exchange,提问作者George Robinson
相关产品推荐
相关产品推荐

