【问题标题】:Fork creates a new process that is exactly the same as its parentFork 创建一个与其父进程完全相同的新进程
【发布时间】:2015-06-21 20:39:13
【问题描述】:

根据我的问题“Fork 创建一个与其父进程完全相同的新进程”标题中所做的假设。我想知道操作系统是如何真正制作分叉的。

考虑到一个繁重的进程(巨大的 RAM 占用),它派生出自己来完成一项小任务(将文件列出到目录中)。根据假设,我预计子进程将与第一个进程一样大。然而,我的常识告诉我,事实并非如此。

它在现实世界中是如何工作的?

【问题讨论】:

  • en.wikipedia.org/wiki/Copy-on-write 在这里可能会有所帮助
  • @Jasper 你是说可执行代码位于 RAM 中并且两个进程共享相同的内存空间?
  • @nowox “man 2 fork”可以帮到你很多。
  • 采用了一种称为 Copy-on-Write(COW) 的机制。这意味着内存的只读部分(那些仅设置了 R(ead) 或 (e)X(ecute) 位的内存页)实际上在 2 个进程之间共享。对于可写的内存,只有当子进程尝试写入时,才会为子进程创建一个页面的私有副本。
  • man 2 vfork 是有趣的历史理由。

标签: linux fork


【解决方案1】:

正如 cmets 中的其他人所提到的,一种称为 Copy-On-Write 的技术减轻了复制父进程的整个内存空间的沉重成本。写时复制意味着内存页面在父子之间以只读方式共享,直到他们中的任何一个决定写入——此时页面被复制并且每个进程都有自己的私有副本。这种技术很容易防止大量复制,这在很多情况下会浪费时间,因为孩子会exec() 或做一些简单的事情然后退出。

详细情况如下:

当您调用fork(2) 时,您产生的唯一直接成本是分配新的唯一进程描述符的成本和复制父页表的成本。在 Linux 中,fork(2)clone(2) 系统调用实现,这是一个更通用的系统调用,允许调用者控制新进程的哪些部分与父进程共享。当从fork(2) 调用时,会传递一组标志以指示没有要共享的内容(您可以选择共享内存、文件描述符等 - 这就是线程的实现方式:通过调用clone(2)CLONE_VM ,意思是“共享内存空间”)。

在底层,每个进程的内存页面都有一个位标志,即 copy-on-write 标志,指示在写入之前是否应复制该页面。 fork(2) 用该位标记进程中的每个可写页面。每个页面还维护一个引用计数。

因此,当一个进程分叉时,内核会在该进程的每个非私有、可写页面上设置 copy-on-write 位,并将引用计数加一。子进程具有指向这些相同页面的指针。

然后,每个页面都被标记为只读,因此尝试写入页面会产生页面错误 - 这是唤醒内核所必需的,以便它有机会看到发生了什么以及需要做什么.

当任一进程写入仍在共享的页面并因此标记为只读时,内核会唤醒并尝试找出页面错误的原因。假设父/子进程正在写入一个合法的位置,内核最终会看到产生了页面错误,因为该页面被标记为 copy-on-write 并且对该页面的引用不止一个.

内核然后分配内存,将页面复制到新位置,然后可以继续写入。

分叉之间有什么不同

你说fork(2) 创建了一个与其父进程完全相同的新进程。这并不完全正确。父母和孩子之间有几个区别:

  1. 进程ID不同
  2. 父进程ID不同
  3. 孩子的资源使用率(CPU时间等)设置为0
  4. 父级拥有的文件锁不会被继承
  5. 子节点上的未决信号集已清除
  6. 已清除子级的未决警报

关于 vfork

vfork(2) 系统调用与fork() 非常相似,但它绝对不会复制——它甚至不会复制父级的页表。随着写时复制的引入,它不再被广泛使用,但从历史上看,它被分叉后调用exec()的进程使用。

自然,在vfork() 之后尝试在子进程中写入内存会导致混乱。

【讨论】:

    【解决方案2】:

    当一个进程分叉时,子进程使用与其父级相同的页表 util 父级或子级写入其空间!所以

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 2018-10-20
      • 2017-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-24
      相关资源
      最近更新 更多