写时复制


#软件架构与思考#


2014-06-12

写时复制,Copy-On-Write,简写为COW。

本文以python中的字符串为例。在python中,字符串是无法修改的。我们看下面的python代码:

s1 = 'abc'
s2 = s1
print s1, id(s1)
print s2, id(s2)

s2 = 'bcd'
print s1, id(s1)
print s2, id(s2)

id()函数用来返回对象的标识符,也就是对象在内存中的地址。下面是一次运行结果:

abc 5155392
abc 5155392
abc 5155392
bcd 34597896

上面的过程,可以用下面的图来表达:

开始时,变量s1和s2同时指向同一个字符串对象'abc',而该对象的引用计数为2。当对s2重新赋值时,发生了写时复制。这时,会在内存中新创建一个内存对象'bcd',s2指向这个新的对象,s1的指向不变。而此时,两个在内存中的字符串对象的引用计数都是1。

如果不使用写时复制的思路,那么在开始时候,在内存中就会有两个内容为'abc'的字符串对象。如果在后期并不会修改s1或者s2,那么会造成资源的浪费。所以可以认为写时复制是一个优化策略。

写时复制的例子是很常见的。

例如,你在某网站上注册一个账号,该网站会给你分配一个默认的图片作为头像,所有的新注册用户都拥有相同的默认头像,这可以类比成很多变量名指向了同一个对象。但是,用户也可以自定义头像(例如通过上传图片等方式),当某个用户自定义头像后,新的头像文件不应该去替换默认的头像文件,不过该网站会确保该用户的头像指向的是新图片,而非默认图片,而这一步就可以类比成写时复制

快照也使用了写时复制的技术。所谓快照,就是获取的一个文件的瞬间状态。我们要获取的瞬时状态可以类比成上面例子中s1变量指向的'abc',在快照期间肯定不能对'abc'进行写操作,所以首先创建s2指向'abc',新写入的数据则保存在s2中。当快照结束后,将s2合并到s1。

Linux写时拷贝技术(copy-on-write)也是一个例子。


( 本文完 )