Sen*_*Sen 13 linux system-calls fork
我想详细了解 fork() 和 vfork() 之间的区别。我无法完全消化手册页。
我还要澄清一下我的一位同事评论“在当前的 Linux 中,没有 vfork(),即使你调用它,它也会在内部调用 fork()”。
Gil*_*il' 24
手册页通常是简洁的参考文档。维基百科是一个更好的地方来进行概念解释。
Fork 复制一个进程:它创建一个与父进程几乎相同的子进程(最明显的区别是新进程具有不同的进程 ID)。特别是,fork(概念上)必须复制所有父进程的内存。
由于这相当昂贵,因此发明了 vfork 来处理不需要副本的常见特殊情况。通常,子进程做的第一件事是加载一个新的程序映像,所以会发生以下情况:
if (fork()) {
# parent process …
} else {
# child process (with a new copy of the process memory)
execve("/bin/sh", …); # discard the process memory
}
Run Code Online (Sandbox Code Playgroud)
该execve
调用加载一个新的可执行程序,这将用新的可执行程序的代码和新的数据存储器替换进程的代码和数据存储器。所以创建的整个内存副本fork
都是徒劳的。
因此,vfork
电话被发明了。它不会复制内存。因此vfork
很便宜,但很难使用,因为您必须确保不访问子进程中的任何进程堆栈或堆空间。请注意,即使读取也可能是一个问题,因为父进程一直在执行。例如,此代码已损坏(它可能会或可能不会工作,具体取决于孩子还是父母首先获得时间片):
if (vfork()) {
# parent process
cmd = NULL; # modify the only copy of cmd
} else {
# child process
execve("/bin/sh", "sh", "-c", cmd, (char*)NULL); # read the only copy of cmd
}
Run Code Online (Sandbox Code Playgroud)
自从 vfork 发明以来,已经发明了更好的优化。大多数现代系统,包括 Linux,都使用写时复制的形式,其中进程内存中的页面不会在fork
调用时复制,而是在父或子首次写入页面时复制。也就是说,每个页面开始时都是共享的,并一直保持共享,直到任一进程写入该页面;写入的进程获得一个新的物理页(具有相同的虚拟地址)。写时复制使 vfork 几乎无用,因为fork
在vfork
可用的情况下不会进行任何复制。
Linux 确实保留了 vfork。该fork
系统调用还必须使这一进程的虚拟内存表的副本,即使它不会复制实际内存; vfork
甚至不需要这样做。在大多数应用程序中,性能改进可以忽略不计。