假设我们有一个特定的父进程,并在内存中存储了任意数量的数据,然后使用fork产生一个子进程。我了解到,为了使操作系统能够在写入时执行复制,内存中包含我们正在修改的数据的特定页面将设置其只读位,并且操作系统将使用在孩子尝试时会导致的异常修改数据以将整个页面复制到内存中的另一个区域,以便子代获得其自己的副本。我不理解的是,如果内存中的特定部分被标记为只读,那么数据最初所属的父级将无法修改数据。那么整个方案如何运作?父级是否会丢失其数据的所有权,并且即使父级本身试图修改数据,也必须执行写入时的复制?
正确,如果任何一个进程写了一个COW页面,它都会触发页面错误。
在页面错误处理程序中,如果该页面应该是可写的,它将分配一个新的物理页面并执行memcpy(newpage, shared_page, pagesize)
,然后更新发生故障的任何进程的页面表,以将新页面映射到该虚拟地址。然后返回到用户空间,以重新运行存储指令。
对于诸如之类的东西fork
,这是一个胜利,因为一个进程通常execve
在触摸了一页(堆栈存储器)后立即立即进行系统调用。execve
销毁该进程的所有内存映射,以新进程有效地替换它。父级再次拥有每个页面的唯一副本。(除了已经进行写时复制的页面(例如,分配有内存的mmap
页面通常会被COW映射到零的单个物理页面,因此读取会命中L1d缓存)。
一个聪明的优化是fork
实际上复制包含堆栈顶部的页面,但仍然对其他所有页面执行惰性COW,前提是假定子进程通常会execve
立即访问并因此将其引用删除到所有其他页面。但是,仍然需要花费父级中的TLB无效才能将所有页面临时翻转为只读和返回。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句