unix fork exec序列真的像听起来那样昂贵吗?

unix fork exec序列真的像听起来那样昂贵吗?,unix,process,exec,fork,Unix,Process,Exec,Fork,我正在阅读关于fork和exec的考试,我的书中说,每当需要在unix系统中运行一个新的(不同的)进程时,您都会在当前进程的fork后面加一个execve 但是,它还表示,每当调用fork时,父进程的整个内存映像都会复制到新进程中 然后我的问题是:如果您有一个内存映像非常大的进程,并且您只想运行一个新进程,该怎么办?如果您要立即替换父进程中的所有数据,那么从父进程中复制这些数据不是浪费资源吗?通常,fork不会实际复制所有内存,而是使用“写时复制”,这意味着只要不修改内存,就会使用相同的页面。但

我正在阅读关于
fork
exec
的考试,我的书中说,每当需要在unix系统中运行一个新的(不同的)进程时,您都会在当前进程的fork后面加一个
execve

但是,它还表示,每当调用
fork
时,父进程的整个内存映像都会复制到新进程中


然后我的问题是:如果您有一个内存映像非常大的进程,并且您只想运行一个新进程,该怎么办?如果您要立即替换父进程中的所有数据,那么从父进程中复制这些数据不是浪费资源吗?

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

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


有关其他解决方案,请参见vWork和posix_spawn

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

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


我认为您可以在UNIX的高级编程中找到这一点。有些系统非常旧(早期UNIX),或者非常特殊(没有mmu的linux),或者非常糟糕(windows通过cygwin),它们确实需要在fork上制作所有页面(“每个字节”)的完整副本,因此潜力是存在的

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

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

旧系统和一些现代系统都实现了一个特殊的vfork()调用,该调用有一些严格的限制(尽管没有POSIX对vfork的要求严格),但出于性能原因,避免使用此副本


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

+1问得好,谢谢。人们常常想知道,为什么答案比问题得到的回报更多。没有问题就没有答案。这个问题也出现在我的脑海中:)这个答案不幸是错误的——过度交付不是unix的一部分,而是某些系统的一种扩展。最常见的(例如Linux)默认情况下,不要要求fork上有完整的16GB可用空间。即使操作系统内核希望检查是否有足够的可用内存,但这并不意味着它需要完整的8GB可用空间,因为这些页面中的许多可以通过只读和只读/执行页面共享。您认为错误,父母在理论上和实践上都可以在子女之前继续。此外,更重要的是,内存拷贝仍然存在。这个答案最接近于描述vWork,而不是某些方面的fork。在vWork中,根本不复制内存,因此主机进程将暂停,直到子进程存在或执行为止。在fork中,在较旧的系统上复制内存,或者在较新的系统中标记为写时复制,并且主机进程能够在多处理器系统中快速恢复。