假设我们有一个父进程,在内存中存储了一些任意数量的数据,我们使用fork来生成子进程。我理解为了让操作系统在写入时执行复制,包含我们正在修改的数据的内存中的某个页面将设置其只读位,并且操作系统将使用在子项尝试时将导致的异常修改数据以将整个页面复制到内存中的另一个区域,以便孩子获得它自己的副本。我不明白的是,如果内存中的特定部分被标记为只读,那么数据最初所属的父级也不能修改数据。那么整个方案如何运作呢?即使父母本身试图修改数据,父母是否会失去其数据的所有权并且必须执行写入复制?
答案 0 :(得分:4)
是的,如果任一进程写入COW页面,则会触发页面错误。
在页面错误处理程序中,如果页面假定是可写的,它会分配一个新的物理页面并执行memcpy(newpage, shared_page, pagesize)
,然后更新出现故障的任何进程的页表。将新页面映射到该虚拟地址。然后返回用户空间以重新运行商店指令。
这是fork
之类的胜利,因为一个进程通常会在触摸通常一页(堆栈内存)之后立即进行execve
系统调用。 execve
会破坏该进程的所有内存映射,有效地将其替换为新进程。父进程再次拥有每个页面的唯一副本。 (除了已经写时复制的页面,例如,使用mmap
分配的内存通常被COW映射到零的单个物理页面,因此读取可以在L1d缓存中命中)。
智能优化将fork
实际复制包含堆栈顶部的页面,但仍会对所有其他页面执行惰性COW,前提是子进程通常会{{1} }立即删除其对所有其他页面的引用。但是,在父级中仍然需要TLB失效才能暂时将所有页面翻转为只读和返回。
答案 1 :(得分:0)
某些UNIX实现在两者之间共享 程序文本 无法修改。或者,孩子可以分享所有 父母的记忆,但在这种情况下,记忆是共享的
copy-on-write
,这意味着当两者中的任何一个想要修改部分内存时,该内存块都会被明确 首先复制以确保修改发生在专用内存中 区域。