如果不采用写时拷贝技术 直接fork子进程 会发生什么?
如上图所示 橙色为父进程所占内存空间 绿色为子进程所占内存空间。
如果子进程只是需要做出一点点和父进程不一样的 其余和父进程均为相同
第一 就会出现复制开销比较大;第二占用内存空间
所以 对fork复制进程的过程进行了优化 写时拷贝技术;
子进程讲共用父进程的地址,在fork的时候 子进程直接把父进程的表页复制过来,只有子进程发生写入(修改)的时候,才会分配内存复制,然后进行相对应的修改
这里进行补充:父子进程复制后 逻辑地址是完全相同的 但是物理地址不一定相同
写时拷贝技术是一种可以推迟甚至免除拷贝数据的技术
传统的 fork() 系统调用直接把所有的资源复制给新创建的进程。这种实现过于简单并且效率低下,因为它拷贝的数据也许并不共享,更糟的情况是,如果新进程打算立即执行一个新的映像,那么所有的拷贝都将前功尽弃。Linux 的 fork() 使用写时拷贝(copy-on-write)页实现。写时拷贝是一种可以推迟甚至免除拷贝数据的技术。内核此时并不复制整个进程地址空间,而是让父进程和子进程共享同一个拷贝。
只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。也就是说,资源的复制只有在需要写入的时候才进行,在此之前,只是以只读方式共享。这种技术使地址空间上的页的拷贝被推迟到实际发生写入的时候才进行。在页根本不会被写入的情况下(举例来说,fork() 后立即调用 exec())它们就无须复制了。
fork() 的实际开销就是复制父进程的页表以及给予进程创建唯一的进程描述符。在一般情况下,进程创建后都会马上运行一个可执行的文件,这种优化可以避免拷贝大量根本就不会被使用的数据(地址空间里常常包含数十兆的数据)。由于 Unix 强调进程快速执行的能力,所以这个优化是很重要的。
解释物理地址和逻辑地址的区别
我们平时所看见的地址 叫做逻辑地址。就如同目录一样,而每一个逻辑地址都指向一个物理地址 就如同目录所对应的页码一样
这里我们可以看出来 父子进程的逻辑地址是完全一样的,但是物理地址不一样
只有一个进程的时候,不需要顾虑太多,也不用去想逻辑地址和物理地址有什么不一样的。
如果是多进程的情况下,逻辑地址相同 对应的物理地址并不一定相同,需要具体的去看各自的表页是否相同(也就是看具体的映射关系)
不同进程的逻辑地址是没有任何比较的意义的;