在 mmap() 的情况下,进程及其子进程如何使用内存?

在 mmap() 的情况下,进程及其子进程如何使用内存?

比方说,我们正在使用 mmap() 创建共享内存。假设总内存大小为 4096。如果我们使用 fork() 系统调用来创建子进程,子进程会使用相同的内存,还是需要拥有自己的内存才能工作?

答案1

fork()父进程的内存空间被克隆到子进程中。作为一种优化,现代操作系统使用 COW(写时复制),因此所有私有内存都与子进程共享,直到其中一个进程执行更改为止。然后受影响的内存页面就会被复制。

子进程和父进程运行在不同的内存空间中。在 fork() 时,两个内存空间具有相同的内容。其中一个进程执行的内存写入、文件映射 (mmap(2)) 和取消映射 (munmap(2)) 不会影响另一个进程。

“两个内存空间具有相同的内容”包括分配的内存mmap()。内存映射被克隆和mmap()/或munmap()分叉后不再影响其他进程。

只有在 fork 之前映射的内存MAP_SHARED(或 Linux 特定的MAP_SHARED_VALIDATE)才会对进程之间传播的内容进行更改。

MAP_SHARED
共享此映射。映射的更新对于映射同一区域的其他进程是可见的,并且(在文件支持的映射的情况下)被传递到底层文件。 (要精确控制何时对底层文件进行更新,需要使用 msync(2)。)

有一些 Linux 特定的映射标志可以以其他方式修改行为:

  • 已用 madvise(2) MADV_DONTFORK 标志标记的内存映射不会跨 fork() 继承。
  • 已用 madvise(2) MADV_WIPEONFORK 标志标记的地址范围中的内存在 fork() 后在子级中清零。 (对于子级中的这些地址范围,MADV_WIPEONFORK 设置仍然保留。)

exec()内存映像被新进程替换,因此所有继承的内存映射fork()都被删除。

所有进程属性都会在 execve() 期间保留,但以下属性除外:
    [...]

  • 不保留内存映射 (mmap(2))。
  • 附加的 System V 共享内存段已分离 (shmat(2))。
  • POSIX 共享内存区域未映射 (shm_open(3))。

相关内容