在我的应用程序中,我需要共享内存
父母和孩子之间(使用fork
+ execl
)。
我使用memfd_create
来分配内存,因为它提供了一个
文件描述符,可以方便地用于孩子
进程(在dup2
之前,discriptor通过execl
绑定到stdin
附加到分配的内存。
我不使用write
和read
- 我使用指针
直接读写内存。
唯一需要解决的难题
是如何获取分配的内存地址
通过fd = memfd_create ...
。
使用mmap
是不可取的,因为它会复制内存,而不是给出内存
内存地址已由memfd_create
分配。
以下代码对此进行了演示。
在其输出中,每个mmap
地址递增4096
,这是内存的大小,由fd
引用:
0x7f98411c1000
0x7f98411c0000
如果mmap
给出了直接地址,
输出中的地址是相同的。
#include <stdio.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
int main(void)
{
int fd = syscall(SYS_memfd_create, "shm", 0);
if (fd == -1) return 1;
size_t size = 4096; /* minimal */
int check = ftruncate(fd, size);
if (check == -1) return 1;
void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) return 1;
void *ptr2 = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr2 == MAP_FAILED) return 1;
printf("%p\n%p\n", ptr, ptr2);
return 0;
}
那么,如何获得直接地址,避免内存重复
按mmap
?
答案 0 :(得分:1)
由于您已经在自己的答案中写下了要点,因此不确定是否仍然需要答案,只是添加此内容以确保它是完整的:
memfd_create创建一个仅内存的文件(意味着它可以存储在磁盘上,尽管可以交换出来)。在您写答案时,它会返回文件描述符。
mmap确保文件描述符后面的文件在内存中(如果是纯内存文件,则不需要任何操作),并为您提供指向该内存的指针。它不会复制内存(从磁盘映射文件时,磁盘之间的复制除外)。如果同一文件被多次映射,则对mmap的每次调用都会保留虚拟内存的新区域,但是所有这些区域都访问物理内存的同一部分。
因此,对这个问题的简短回答是您误解了mmap;它不会复制内存,是解决您问题的完美解决方案。
答案 1 :(得分:0)
我们从memfd_create
获取了一个文件描述符,而不是物理地址。
文件描述符是一个句柄,通过它我们可以访问内存
(即,这是从文件描述符到内存的映射)。一份文件
描述符比内存地址更方便使用:
可以将其传递给分叉的进程等(请参阅OP)。
mmap
仅映射物理地址(由文件描述符引用)
到虚拟地址。虚拟内存地址实际上是 the 内存
地址,因为用户永远不会看到物理地址。
每个mmap调用返回一个不同的虚拟地址,所有这些虚拟地址
被内核映射到相同的物理地址。