在fork()之前或之后在磁盘文件上调用mmap()有什么区别?

3
我一直在努力理解mmap()如何与磁盘支持的文件配合使用,现在我基本上已经懂了,但我还有一个问题。
在主进程分叉出许多工作子进程,并使用文件支持的只读mmapped db的情况下,如果mmaps在分叉之前发生在主进程中,还是在子进程中,这是否重要?
我的理解是,如果在分叉之前它发生在主进程中,则在内存页表中,所有映射的页面都会被设置为在读取时引发页故障,从而触发内核从磁盘(或页面缓存)加载页面,在分叉后,一个子进程对页面的读取将使页面在mmap中准备好供其他子进程读取,而不会导致重大页故障。
但是,如果在分叉后映射在子进程中发生,其他工作子进程是否可以共享这些已加载的页面的好处 - 他们实际上是否在使用相同的底层mmap?还是每个工作子进程都必须触发一个页故障并自己加载每个页面?

页面错误不仅限于一个进程。文件的某一页要么在内存中,要么不在。 - Barmar
@Barmar 这也不完全正确。页面错误中断是针对进程特定的,当它们触及用户空间地址时发生。 - Antti Haapala -- Слава Україні
@AnttiHaapala 这是因为它们可以具有不同的保护模式(同一页在P1中可能是只读的,但在P2中是可读写的),因此它们必须通过页面故障机制来检查这一点吗?这仍然不会影响内存是否需要分页。 - Barmar
1个回答

2
这对页面错误活动没有影响。文件的页映射是全局的,它说明特定页面是否在RAM中。具有映射文件的每个进程的PTE都指向这个公共数据结构。只有第一个尝试访问不在RAM中的页面的进程会发生页面错误。这将触发将其读入,并且尝试访问相同页面的其他进程将能够使用该RAM。
两种情况之间的一个区别是分配给映射块的虚拟地址是否相同。如果在fork之前调用mmap,则所有子进程都将复制该地址。如果在fork之后调用mmap,则它们可能获得不同的地址。在所有进程中使用相同的地址允许您在进程之间传递指向映射块的指针,如果需要,可以在块内的对象之间使用指针。如果它们不在相同的地址上,则需要使用偏移量,并且所有进程都必须将偏移量添加到基地址。

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