何时使用mmap MAP_FIXED?

9

我一直在研究mmap函数的不同标志,即MAP_FIXED、MAP_SHARED、MAP_PRIVATE。有人能解释一下MAP_FIXED的目的吗?毕竟并不能保证地址空间会被使用。

2个回答

18

MAP_FIXED是内存映射的dup2,在与文件描述符中dup2相同的情况下非常有用:当您想要执行一个替换操作时,该操作可以原子地重新分配资源标识符(在MAP_FIXED的情况下是内存范围,在dup2的情况下是fd),以引用新资源,而无需担心可能会出现的竞争条件,在这种情况下,如果您首先释放旧资源,然后尝试为新资源恢复它。

例如,考虑加载共享库(由动态加载器)。它由至少三种类型的映射组成:程序代码和来自可执行文件的只读数据的读取+执行映射,已初始化数据的读写映射(也来自可执行文件,但通常具有不同的相对偏移量),以及读写零初始化的匿名内存(对于.bss )。将它们作为单独的映射创建将无法工作,因为它们必须相对于彼此保持固定的相对地址。因此,您首先创建所需总长度的虚拟映射(此映射的类型无关紧要),而不使用MAP_FIXED仅仅是为了在内核分配的位置上保留足够数量的连续地址范围,然后使用MAP_FIXED根据需要覆盖此范围的部分,以创建所需的三个或更多映射。

另外,请注意,始终将MAP_FIXED与硬编码地址或随机地址一起使用是错误的。正确使用MAP_FIXED的唯一方法是替换先前成功调用mmap而没有使用MAP_FIXED分配地址的现有映射,或以其他方式您感到可以安全地替换整个页面。这方面也完全类似于dup2;如果调用者没有针对目标fd打开文件并打算替换该文件,则始终将dup2用于该情况是一个错误。


然后,您可以使用MAP_FIXED将所需的三个或更多映射与此范围的部分重叠。在使用MAP_FIXED进行第二次映射后,原始虚拟映射是否可以立即释放? - user3882729
@user3882729:如果有任何未使用的部分,可以取消映射,但已经使用的部分已经通过映射“释放”了。如果您尝试再次取消映射,则不会取消初始虚拟映射,而是要取消您想要放置的实际映射。 - R.. GitHub STOP HELPING ICE

2
如果您要加载的文件包含指针,则需要在固定位置加载它,以确保指针正确。在某些情况下,这只是一种优化。
  • 不可重定位的可执行文件必须在固定地址加载。

  • 共享内存可能包含指针。

  • 使用预绑定的可执行文件将尝试在预定的内存位置加载动态库作为优化,但如果使用不同位置(或库已更改),则会回退到正常加载技术。

因此,MAP_FIXED不是典型的用法。

1
我认为这并没有回答什么时候使用它的问题。 - R.. GitHub STOP HELPING ICE
@R..:你说得对。我完全忘记了重新映射。 - Dietrich Epp
1
另一个用例(但并非这个标志的真正“目的”)是使某些数据(例如大型、计算成本高昂的图形)具有位置相关性,并且能够将其保存到文件以加速后续运行。我相当确定这是不被认可的,但是我已经能够通过MMAP_FIXED_NOREPLACE和malloc wrapper实现一些酷炫的事情了。 - Fábio Santos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接