fork后发生了什么——内存篇

/ 0评 / 0

fork出来的子进程完全拷贝了父进程的地址空间,其中自然就包括了数据段、栈、堆等,我们常用的一种方式是:在fork出来的子进程中调exec函数族来进行后续工作,exec函数族本质上都是execve系统调用,这个函数族会丢弃现存的代码段,并构建新的数据段、栈、堆。在这种背景下,fork时让子进程完全拷贝父进程的数据段、栈和堆怎么说都是不明智的,因为exec函数族会毫不留情的抛弃刚刚辛苦拷贝的内存。为了解决这个弊病,linux引入了写时拷贝——copy-on-write技术
写时拷贝是指把子进程PCB的页表项指向与父进程相同的物理内存页,这样只拷贝父进程的页表项就可以了,当然,要把这些页面标记为只读。如果父子进程都不修改内存的内容,大家便相安无事,供用一份物理内存,一旦父子进程中有任何一方尝试修改,就会引发缺页异常(page fault)。此时,内核会尝试为这份共享的物理页创建一份拷贝,并将原物理页中的内容真正的复制带新的物理页中,让父子进程真正的各自拥有自己的物理内存页,然后在页表中将相应的表项标记为可写。
因此,对于没有修改的页面,内核并没有真正地复制物理内存页,仅仅是复制了父进程的页表。这种机制无疑是很大程度上提高了fork的性能,从而使内核可以最快速的创建一个新进程。

fork中与内存相关的执行流

        

其中pud、pmd、pte是linux的四级页表,如下

    

上面的执行流就相当好理解每一步是在干什么了,最后关于copy_one_pte函数,在内核中表明了:无论父子进程在写时拷贝时都会给内存进行写保护

        

发表评论

电子邮件地址不会被公开。 必填项已用*标注