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)也是一个例子。