首页 > 代码库 > 写时拷贝(copy-on-write) COW技术

写时拷贝(copy-on-write) COW技术

时间:2014.05.06

地点:基地二楼

----------------------------------------------------------------------------------

一、写时拷贝的概念——COW技术在Linux进程上的应用

   Linux在使用fork()函数进程创建时,传统fork()的做法是系统把所有的资源复制给新创建的进程,这种方式不仅单一,而且效率低下。因为所拷贝的数据或别的资源可能是可以共享的。现在Linux的fork()使用写时拷贝页来实现新进程的创建,它是一种可推迟甚至避免数据拷贝的技术,刚开始时内核并不会复制整个地址空间,而是让父子进程共享地址空间,只有在写时才复制地址空间,使得父子进程都拥有独立的地址空间,即资源的复制是在只有需要写入时才会发生,因此而称之为Copy on Write(COW)。在此之前都是以读的方式去和父进程共享资源,这样,在页根本不会被写入的场景下,fork()立即执行exec(),无需对地址空间进行复制,fork()的实际开销就是复制父进程的一个页表和为子进程创建一个进程描述符,也就是说只有当进程空间中各段的内存内容发生变化时,父进程才将其内容复制一份传给子进程,大大提高了效率。

  那么,这样子进程的物理空间中没有代码,又是如何取指令去执行exec调用的呢?

  其实,在fork()之后,exec()之前,子进程和父进程是共享物理空间(内存区)的,子进程的代码段,数据段和堆栈都指向父进程物理空间,即两者的虚拟空间不同,但物理空间其实是同一个,当父进程或者子进程有需要修改段的行为时,再为子进程分配相应段的物理空间,若不是exec则内核会给子进程的数据段,堆栈段分配相应的物理空间,至此二者各自有各自的物理空间,互不影响。而代码段则继续共享父进程的物理空间,因为两者的代码完全相同,但如果是因为exec,,由于二者的执行的代码不同,则也需为子进程分配代码段的物理空间。

----------------------------------------------------------------------------------

二、COW技术在C++中string实现上的应用

  看如下代码:

string str1="hello world";
string srr2=str1;

此时str1和str2的存放地址其实是一样的

之后执行

str1[1]=‘a‘;
str2[1]=‘b‘;
执行修改后,此时str1的地址会发生变化,而str2的地址还是原来的。即在复制对象时,并不真正为新对象开辟内存空间,而是在新对象的内存映射表中设立一个指针,指向源对象,这样在进行读操作时因为并不修改对象,并不会给源对象带来影响,当某一时刻要对某一对象进行修改时,即写操作时,再将对象复制到新的内存空间中去,在这上面执行修改,以避免相互之间的影响。这样做的一个好处也是尽可能提高效率。

当然,不同的编译器string的实现方式不一样,有些编译器并不使用COW技术去实现。

----------------------------------------------------------------------------------

三、COW并不那么完美

  COW是一种很重要的优化手段,核心是懒惰处理实体资源请求,在多个实体资源之间只是共享资源,起初是并不真正实现资源拷贝,只有当实体有需要对资源进行修改时才真正为实体分配私有资源。但COW技术亦有它的优点和缺点。下面逐一分析:

1.COW技术科减少分配和复制大量资源时带来的瞬间延时,但实际上是将这种延时附加到了后续的操作之中。

2.COW技术科减少不必要的资源分配。比如fork进程时,并不是所有的页面都需要复制,父进程的代码段和只读数据段都不被允许修改,所以无需复制。