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

What is the difference between calling mmap() on a disk file before or after a fork?

我一直在努力理解 mmap() 如何与 disk-backed 文件一起工作,并且基本上明白了,但我仍然有这个问题。

在主进程分叉一堆工作进程 child 和 file-backed read-only mmapped db 的情况下,mmaps 是否发生在主进程中是否重要分叉之前的进程,还是 child 进程中的进程?

我的理解是,如果发生在fork之前的master进程,那么在内存页table,所有mapped 页面被设置为在读取页面时发生页面错误,触发内核从磁盘(或页面缓存)加载页面,并且在 fork 之后 child 读取页面将意味着该页面位于 mmap 中,可供其他 children 读取而不会导致重大页面错误。

但是如果 mmap 发生在 fork 之后的 child 进程中,其他工作人员 children 是否可以从共享这些加载的页面中获益——他们实际上都使用相同的方法吗?底层mmap?还是每个工作人员 child 都必须触发页面错误并自己加载每个页面?

页面错误没有区别activity。文件的页面映射对于 OS 是全局的,它表示特定页面是否在 RAM 中。每个具有文件映射的进程的 PTE 都指向这个公共数据结构。只有第一个尝试访问不在 RAM 中的页面的进程才会出现页面错误。这将触发它被读入,并且尝试访问同一页面的其他进程将能够使用该 RAM。

这两种情况的一个区别是分配给映射块的虚拟地址是否相同。如果您在分叉之前调用 mmap,则该地址将被复制到所有子项中。如果您在分叉后调用 mmap,它们可能会获得不同的地址。如果需要,在所有进程中使用相同的地址允许您将指针传递到进程之间的映射块中。块内的对象之间可以有指针。如果它们不在同一地址,则需要使用偏移量,并且所有进程都必须将偏移量添加到基地址。