如何从memfd_create获取内存地址?

问题描述 投票:1回答:2

在我的应用程序中,我需要在父母和孩子之间共享记忆(使用fork + execl)。我使用memfd_create来分配内存,因为它提供了一个文件描述符,可以方便地在子进程中使用(在dup2之前,discriptor通过execl绑定到stdin)以附加到分配的内存。

我不使用writeread - 我使用指针直接读写内存。

唯一需要解决的难题是如何获取通过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的内存重复?

shared-memory mmap
2个回答
1
投票

不确定你是否还需要答案,因为你已经在自己的答案中写了主要观点,但只是添加它以确保它是完整的:

memfd_create创建一个仅限内存的文件(意味着它不存储在磁盘上,尽管它可以被换出)。当您在答案中写下时,它会返回一个文件描述符。

mmap确保文件描述符后面的文件在内存中(在仅内存文件的情况下不需要操作),并为您提供指向该内存的指针。它不会复制内存(从磁盘映射文件时,从磁盘到内存除外)。如果多次映射同一文件,则每次调用mmap都会保留一个新的虚拟内存区域,但所有这些区域都会访问相同的物理内存部分。

所以对你的问题的简短回答就是你误解了mmap;它不会复制内存,它是解决您问题的完美方案。


0
投票

我们从memfd_create获取文件描述符而不是物理地址。文件描述符是一个句柄,通过它我们可以访问内存(即,它是从文件描述符到内存的映射)。文件描述符比内存地址更方便使用:它可以传递给分叉进程等(参见OP)。

mmap只是将物理地址(由文件描述符引用)映射到虚拟地址。虚拟内存地址实际上是内存地址,因为用户永远不会看到物理地址。每个mmap调用都返回一个不同的虚拟地址,所有这些地址都由内核映射到同一个物理地址。

© www.soinside.com 2019 - 2024. All rights reserved.