C|内存管理|COW in Linux

2021-11-22 11:21:43 浏览数 (2)

简介

众所周知,在fork时,属于进程private的内存页将会进行COW机制。所谓COW,就是一个资源如果需要值拷贝,在读时不创建出副本,仅当写时再创建。这样的话,就可以方便地判断出什么资源需要真的进行拷贝,而能够共享则无需拷贝,从而减少了复制的开销。

这个流程分为两部分:

Fork

设置父子进程的所有内存页的标志为write protected,

而在mmap中被标识为shared的内存则会通过wp_page_reuse标记为wriable

因为谁先写不知道,所以两者都应该是wp,都能进行COW机制。

这里产生了一个问题:

假如父子进程都使用COW,那么在子进程已经copy过的情况下,父进程再copy一次就会造成浪费。(此时原本的一个物理页会对应三个物理页,copy两次)

而且父子同时使用副本的话,原页在没有进程使用的情况下应该如何释放?如果使用计数的话,我们可以知道这个页在cnt==0时应该gc,但是假如我们已经知道了计数,我们完全可以在cnt==1时就不再复制。(此时原本的一个物理页会对应两个物理页,copy1次)

Linux中,也的确很节省地使用了这样的方式。

COW

首先和常识相同,write这些页会触发page fault:

handle_pte _fault

linux使用handle_pte_fault函数处理:

如果vma是writable但是却触发了write fault,则调用do_wp_page(write protect)

do_wp_page

在这个函数里,kernel将会根据物理页遍历所有对应的虚拟页(使用链表)求map cnt,如果map cnt为1,说明当前物理页仅被一个进程使用,不需要COW。(这个过程加锁,防止cnt不同步)。这种情况下,则调用 wp_page_reuse 。

wp_page_reuse

这个函数会在两种情况下调用,要么是上述map cnt==1,要么是mmap里声明为shared(VM_SHARED),原本write_protect的页会直接被标识为writable,即跳过copy。

总结

COW机制下,父子进程的页都会被标记为write protect

  • 父子进程均有可能进行copy
  • 最后一个写的进程不会进行copy,而是直接使用原本的物理页。

0 人点赞