如何从memfd_create获取内存地址?
How to get memory address from memfd_create?
在我的应用程序中我需要共享内存
父子之间(使用 fork
+execl
)。
我使用 memfd_create
来分配内存,因为它提供了
文件描述符,可以方便地在子进程中使用
过程(描述符在 execl
之前通过 dup2
绑定到标准输入)
附加到分配的内存。
我不使用 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
?
我们从 memfd_create
获取文件描述符而不是物理地址。
文件描述符是一个句柄,通过它我们可以访问内存
(即,它是从文件描述符到内存的映射)。一份文件
描述符比内存地址更方便使用:
它可以传递给分叉进程等(参见 OP)。
mmap
只是映射物理地址(由文件描述符引用)
到一个虚拟地址。一个虚拟内存地址其实就是内存
地址,因为用户永远不会看到物理地址。
每个 mmap 调用 returns 一个不同的虚拟地址,所有这些
被内核映射到相同的物理地址。
不确定您是否还需要一个答案,因为您已经在自己的答案中写下了要点,但只需添加这个以确保它是完整的:
memfd_create 创建一个内存文件(这意味着它不存储在磁盘上,尽管它可以被换出)。正如您在回答中所写,它 returns 一个文件描述符。
mmap 确保文件描述符后面的文件在内存中(在内存文件的情况下不需要任何操作),并为您提供指向该内存的指针。它不复制内存(从磁盘映射文件时从磁盘到内存除外)。如果同一个文件被多次映射,每次调用 mmap 都会保留一个新的虚拟内存区域,但所有这些区域都访问物理内存的同一部分。
所以对你的问题的简短回答是你误解了mmap;不拷贝内存,完美解决你的问题
在我的应用程序中我需要共享内存
父子之间(使用 fork
+execl
)。
我使用 memfd_create
来分配内存,因为它提供了
文件描述符,可以方便地在子进程中使用
过程(描述符在 execl
之前通过 dup2
绑定到标准输入)
附加到分配的内存。
我不使用 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
?
我们从 memfd_create
获取文件描述符而不是物理地址。
文件描述符是一个句柄,通过它我们可以访问内存
(即,它是从文件描述符到内存的映射)。一份文件
描述符比内存地址更方便使用:
它可以传递给分叉进程等(参见 OP)。
mmap
只是映射物理地址(由文件描述符引用)
到一个虚拟地址。一个虚拟内存地址其实就是内存
地址,因为用户永远不会看到物理地址。
每个 mmap 调用 returns 一个不同的虚拟地址,所有这些
被内核映射到相同的物理地址。
不确定您是否还需要一个答案,因为您已经在自己的答案中写下了要点,但只需添加这个以确保它是完整的:
memfd_create 创建一个内存文件(这意味着它不存储在磁盘上,尽管它可以被换出)。正如您在回答中所写,它 returns 一个文件描述符。
mmap 确保文件描述符后面的文件在内存中(在内存文件的情况下不需要任何操作),并为您提供指向该内存的指针。它不复制内存(从磁盘映射文件时从磁盘到内存除外)。如果同一个文件被多次映射,每次调用 mmap 都会保留一个新的虚拟内存区域,但所有这些区域都访问物理内存的同一部分。
所以对你的问题的简短回答是你误解了mmap;不拷贝内存,完美解决你的问题