今天主要探讨一下读时共享 写时复制的原理
1. 父子进程fork之后,数据的异同是什么?
父子进程之间,刚刚创建子进程后(在fork后):
(1)父子相同处: 全局变量、.data、.bbs、.text、栈、堆、环境变量、用户ID、宿主目录(进程用户家目录)、进程工作目录、信号处理方式等等,即0~3G的用户空间是完全一样的。
(2)父子不同处: 进程ID、fork返回值、父进程ID、进程运行时间、闹钟(定时器)、未决信号集。
2. 子进程真的在fork之后从父进程的0-3G地址空间完全拷贝一份吗?
其实,父子进程间遵循读时共享写时复制的原则,以此来减少复制时的开销。具体来讲只有进程空间的各段的内容要发生变化时(子进程或父进程进行写操作时,都会引起复制),才会将父进程的内容复制一份给子进程。在fork之后两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。即父子进程在逻辑上仍然是严格相互独立的两个进程,各自维护各自的参数,只是在物理上实现了读时共享,写时复制。
下面用图来说明:
1)fork函数创建子进程后,见图1,内核只为新生成的子进程创建虚拟空间结构,它们来复制于父进程的虚拟空间结构,但是不为这些段分配物理内存,它们共享父进程的物理空间。
2)如下图2,直到父子进程中有更改相应段(用户空间中)的行为发生时,再为子进程相应的段分配物理空间。
参考:
1. 进程共享(读时共享写时复制copy-on-write)原理详解——超经典.
2. 进程共享(读时共享写时复制).