前言
我们知道,早期的UNIX在fork()进程时,会将父进程的地址空间完整的复制一份,这个操作非常耗时,通常要进行如下步骤:
- 为子进程的页表分配页面
- 为子进程的页分配页面
- 初始化子进程的页表
- 把父进程的页复制到子进程对应的页中
而现代的Unix及Linux采用了一种称为写时复制的技术,以达到推迟甚至避免复制数据的目的。
正文
写时复制的做法是,子进程和父进程在fork()时并不马上复制,而是暂时共享内存空间,随后只要父进程或者子进程试图写共享的内存就会产生一个异常, 这时内核才把内存空间进程复制。
如果fork()完子进程后,直接调用exec()执行新程序,这时则根本不会复制父进程的页,而fork()完子进程后,直接调用exec()执行新程序,是一种很常用的做法,这样写时复制就大大提高了效率。
通常fork之后内核会通过将子进程放在队列的前面,以让子进程先执行,以免父进程执行导致写时复制,而后子进程执行exec系统调用,因无意义的复制而造成效率的下降。
调用exec()执行新程序后,子进程的代码段,全局变量区,堆栈段将是全新的,与父进程完全隔离开。