如何实现非零填充的大内存匿名映射(MAP_ANONYMOUS)?
解决方案:保留自定义数据的大内存映射方法
首先明确:《Linux编程接口》确实提到,无文件描述符的匿名映射(MAP_ANONYMOUS)会将映射区域初始化为0,所以直接用这种方式没法保留你预先准备的自定义数据。下面是几种可行的实现思路:
方法1:先匿名映射,再拷贝源数据
这是最直接的方案:先通过mmap创建匿名映射区域,再用memcpy把自定义数据拷贝到映射区域里。
#include <sys/mman.h> #include <string.h> // 假设source_data是已填充好的1GB数据缓冲区 void *source_data = ...; size_t map_size = 1024 * 1024 * 1024; // 创建匿名映射 void *mapped_area = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (mapped_area == MAP_FAILED) { // 错误处理 } // 拷贝自定义数据到映射区域 memcpy(mapped_area, source_data, map_size);
注意:1GB的数据拷贝会占用一定CPU和内存带宽,如果对性能要求极高,这个方案可能不是最优选择。
方法2:使用临时文件映射
创建一个临时文件,将自定义数据写入文件后再映射该文件,这样映射出来的区域直接就是你的自定义数据。
#include <sys/mman.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <string.h> size_t map_size = 1024 * 1024 * 1024; void *source_data = ...; // 创建临时文件 char tmp_path[] = "/tmp/mymap.XXXXXX"; int fd = mkstemp(tmp_path); if (fd == -1) { // 错误处理 } // 扩展文件大小到1GB if (ftruncate(fd, map_size) == -1) { // 错误处理 } // 写入自定义数据到文件 if (write(fd, source_data, map_size) != map_size) { // 错误处理 } // 映射文件到内存 void *mapped_area = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (mapped_area == MAP_FAILED) { // 错误处理 } // 用完后关闭文件描述符(映射依然有效) close(fd); // 不需要临时文件时删除 unlink(tmp_path);
如果想避免磁盘IO开销,可以用Linux 3.11+支持的O_TMPFILE标志创建内存中的临时文件,数据只存在于页缓存,不会刷到磁盘(除非系统内存不足):
int fd = open("/tmp", O_TMPFILE | O_RDWR | O_EXCL, 0600);
方法3:使用memfd_create(推荐)
这是Linux特有的系统调用,创建一个匿名的内存文件描述符,本质是在内存中模拟文件,既能写入数据又能通过mmap映射,完全没有磁盘IO开销,非常适合大内存场景。
#include <sys/mman.h> #include <sys/memfd.h> #include <unistd.h> #include <string.h> size_t map_size = 1024 * 1024 * 1024; void *source_data = ...; // 创建匿名内存文件描述符 int fd = memfd_create("my_mem_map", MFD_CLOEXEC); if (fd == -1) { // 错误处理 } // 扩展文件大小到1GB if (ftruncate(fd, map_size) == -1) { // 错误处理 } // 写入自定义数据 if (write(fd, source_data, map_size) != map_size) { // 错误处理 } // 映射到内存 void *mapped_area = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (mapped_area == MAP_FAILED) { // 错误处理 } // 关闭文件描述符,映射依然有效 close(fd);
优点:既避免了匿名映射的清零问题,又没有磁盘IO开销,性能最优,是大内存场景的首选方案。
内容的提问来源于stack exchange,提问作者LeBron GanDalf
相关产品推荐
相关产品推荐

