Linux 2.6下模拟memfd_create的更优替代方案技术咨询
针对Linux 2.6替代memfd_create的更优方案
刚好之前维护老Linux 2.6项目时碰到过一模一样的场景,来给你分享几个更优的替代方案,解决你对mkstemp+unlink方式的不满:
1. 优先推荐:shm_open + shm_unlink组合
Linux 2.6已经完全支持POSIX共享内存API的shm_open(内核2.4+就引入了),它创建的文件默认位于/dev/shm——这是一个基于内存的tmpfs文件系统,完全没有磁盘IO开销,完美匹配你避免物理文件开销的需求。
实现逻辑:
- 用
shm_open创建一个带随机后缀的临时共享内存对象(避免命名冲突) - 立即调用
shm_unlink删除该对象的文件系统入口,这样即使进程意外崩溃,内核也会自动回收这块内存(不会像普通文件那样残留磁盘空间) - 通过
ftruncate设置内存区域的大小,再用mmap映射到进程地址空间
示例代码:
#include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> int main() { // 生成带随机后缀的共享内存名称,避免冲突 char shm_name[] = "/tmp_shm_obj_XXXXXX"; int fd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); if (fd == -1) { perror("shm_open failed"); exit(EXIT_FAILURE); } // 立即unlink,移除文件系统中的入口 if (shm_unlink(shm_name) == -1) { perror("shm_unlink failed"); close(fd); exit(EXIT_FAILURE); } // 设置共享内存区域的大小(按需调整) off_t size = 4 * 1024 * 1024; // 4MB if (ftruncate(fd, size) == -1) { perror("ftruncate failed"); close(fd); exit(EXIT_FAILURE); } // 映射到进程地址空间 void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { perror("mmap failed"); close(fd); exit(EXIT_FAILURE); } // 这里可以使用映射后的内存区域... // 清理资源 munmap(addr, size); close(fd); return EXIT_SUCCESS; }
这个方案的优势:
- 完全基于内存,无磁盘IO开销,比mkstemp+unlink(依赖/tmp是否为tmpfs)更可靠
- API更贴合“匿名内存对象”的需求,shm_unlink后内核自动回收机制更稳定
- 保留了文件描述符,满足你需要传递fd给mmap或其他操作的场景
2. 极简方案:MAP_ANONYMOUS直接映射(无需fd时使用)
如果你不需要保留文件描述符,只是需要一块匿名的内存区域,那Linux 2.6支持的MAP_ANONYMOUS(或MAP_ANON别名)是最直接的选择——连文件都不用创建,直接调用mmap即可:
void *addr = mmap(NULL, 4 * 1024 * 1024, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
注意:这个方案只适用于不需要操作fd的场景(比如不需要传递给其他进程、不需要调整内存大小等),如果你的业务逻辑必须依赖fd,那就还是用第一个方案。
3. 备选方案:手动挂载tmpfs(不推荐)
如果因为某些限制无法使用shm_open,可以手动挂载一个tmpfs到临时目录,然后在里面用mkstemp创建文件——这样文件也会存在内存中,无磁盘开销。但这个方案需要root权限(或提前在/etc/fstab配置),操作繁琐,不如前两个方案简洁,所以一般不推荐。
内容的提问来源于stack exchange,提问作者xcvii
相关产品推荐
相关产品推荐

