linux在fork进程时,只是为子进程创建一个数据结构,使子进程地址空间映射到与父进程相同的物理内存空间。
而linux的内存空间分为以下几段:
子进程在刚fork生成时,完全共享父进程的进程物理空间,即采用写时复制的方式共享,在子进程或者父进程对进程空间进行写入时,则需要对对应的页(或者说块)进行复制,即为子进程分配独立的物理空间。那么每次复制的单元是什么呢?是不是段呢(代码段,数据段,堆,栈,BSS段,内存映射段),是不是整个进程空间呢。应该是页,就是说当某一页被写入时,该页就会被复制到为子进程分配的独立物理空间中,而其他页还是共享。如父进程中有一个变量,再说块号为x的内存中,子进程修改这个变量的值时,就会发生写时复制,块号为x的整块的内容会被复制到为子进程分配的物理空间中,其他空间继续共享。
为什么使用写时复制的方式呢,如果不采用写时复制,直接为子进程分配独立空间然后把父进程的进程空间的内容复制到过去,那么可能父进程中的内容子进程根本就不需要或者不会去写入,只会去读取,那么直接复制就会浪费空间。为什么要以页为单位进行复制,如果写入几个字节到数据段,就拷贝整个数据段到子进程独立物理空间的话,那么其实跟直接fork时复制没什么区别了,就违背了写时复制的初衷,因为如果写入几个字节就拷贝整段,那么每段内容一般都会写入一点,那么不就要全复制了。
因为有了写时复制,那么其实对于像preloadClasses和preloadResources预加载的内容,其实子进程一般都是只读的,所以比较省内存,而且也为子进程省了时间。