【问题标题】:Is the unix fork exec sequence really as expensive as it sounds?unix fork exec 序列真的像听起来那么昂贵吗?
【发布时间】:2012-01-12 04:12:30
【问题描述】:

我正在阅读有关 forkexec 的考试信息,我的书说,每当需要在 unix 系统中运行一个新的(不同的)进程时,你会 fork 当前进程,然后是 @ 987654323@.

不过,它也表示,每当调用fork 时,父进程的整个内存映像都会复制到新进程中。

那么我的问题是:如果您有一个内存映像非常大的进程,而您只想运行一个新进程怎么办?直接替换掉父进程的所有数据,是不是很浪费资源?

【问题讨论】:

  • +1 好问题,谢谢。经常想知道答案是如何获得比问题更多的回报的。没有问题就没有答案。这个问题也在我的脑海中:)

标签: unix process exec fork


【解决方案1】:

一些非常老的系统(早期的 unix),或者非常特殊的(mmu-less linux)或者非常糟糕的(通过 cygwin 的 windows)确实需要在 fork 上制作所有页面(“每个字节”)的完整副本,所以潜力是存在的。

现代 unix 内核不会复制所有进程内存,而是选择制作虚拟副本。虽然这仅涉及复制的一小部分(需要复制页表),但这仍然可能是数兆字节并且需要大量时间。

所以答案是,一般来说是的,但大多数现代实现使用硬件来制作快速虚拟副本,但即使是虚拟副本也不是免费的。

旧的和一些现代的系统都实现了一个特殊的 vfork() 调用,它有一些严格的限制(虽然没有 POSIX 对 vfork 的要求那么严格),但出于性能原因,请避免使用这种副本。

为了给出一些实际的数字,在我的 GNU/Linux 系统上,我可以从 20MB 的进程每秒 fork+exit 1340 次,但在 2000MB 的进程上只能每秒 235 次。在这两种情况下,vfork+execve 都更快,这有点不直观,因为很多人认为“fork 很快”,“execve 一定很慢”。

【讨论】:

    【解决方案2】:

    除非其中一个进程修改了内存,否则不会进行内存复制,在这种情况下,页面将被复制,并且如果您在调用 fork() 后立即在子进程中调用 exec(),则不会进行复制.

    实际上我认为要确保 exec() 总是在父进程写入内存之前被调用,子进程总是首先运行。

    我想你可以在 UNIX 中的高级编程

    中找到这个

    【讨论】:

    • 你想错了,父母可能会在孩子之前继续,无论是理论上还是实践上。此外,更重要的是,仍然制作了内存副本。
    • 这个答案最贴切地描述了vfork,而不是在某些方面fork。在 vfork 中根本不会复制内存,因此主机进程 暂停,直到子进程存在或执行。在 fork 中,内存在旧系统上被复制或在新系统中标记为写入时复制,并且主机进程能够在多处理器系统中快速恢复。
    【解决方案3】:

    通常,fork 实际上并不复制所有内存,而是使用“写时复制”,这意味着只要不修改内存,就会使用相同的页面。但是,为了避免以后没有足够的内存(如果进程写入内存),必须分配足够的内存。

    这意味着在不允许过度使用内存的系统上从大型进程派生内存必须是可用的。因此,如果您有一个 8 GB 的进程分叉,那么至少在短时间内必须有 16 GB 可用。

    另请参阅 vfork 和 posix_spawn 以了解其他解决方案。

    【讨论】:

    • 不幸的是,这个答案是错误的——过度使用不是 unix 的一部分,而是某些系统的扩展。最常见的(例如 Linux)默认情况下不需要在 fork 上提供完整的 16GB。
    • 即使操作系统内核想要检查是否有足够的可用内存,但这并不意味着它需要完整的 8 GB 可用内存,因为其中许多页面可以通过只读方式共享并仅读取/执行页面。
    猜你喜欢
    • 2013-05-07
    • 2011-08-10
    • 2012-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-13
    • 2010-11-28
    • 2012-12-16
    相关资源
    最近更新 更多