写时复制技术及其应用

Copy On Write(COW) 最先从Linux的fock中学到, 目的是在创建子进程时不用真的复制全部的内存, 而是共享这些内存, 当父进程或子进程对共享内存进行更改时, 才复制一份.这样对于那些fork不需要父进程任何东西, 直接exec的程序来说, 大大减少了无用的复制.

但是这个技术不仅仅用于Linux上, 更是一种朴素的思想, 比如C++的共享字符串, Redis 的bgsave, raft的快照都有使用.

在介绍怎么应用之前, 先想明白几个细节的地方

细节

  1. 更改时复制, 复制的粒度是什么?

    写操作设计到的页.

    当子进程被创建的时候, 共享的内存会被标记为只读. 当任何人想要修改这段内存, MMU会报异常, 然后内核会请求复制页, 然后再次提交写入到MMU.

  2. 子进程/父进程写入新的数据

    如果写入的数据是在原来的页上, 那么会复制写入的页, 如果需要创建一个新页, 那么不会共享.

应用

C++ 共享字符串

Copy On Write(写时复制)使用了“引用计数”(reference counting),会有一个变量用于保存引用的数量。当第一个类构造时,string的构造函数会根据传入的参数从堆上分配内存,当有其它类需要这块内存时,这个计数为自动累加,当有类析构时,这个计数会减一,直到最后一个类析构时,此时的引用计数为1或是0。此时,程序才会真正的Free这块从堆上分配的内存。

当任何一个变量要修改内存时, 会new出一个空间,然后使得引用计数-1.

Redis bgsave | raft 快照

redis 提供一个命令将内存中的数据保存到文件中, 这个操作不会中断Redis处理其他请求, 数据仍可以进行增删改查. 实现方式就是Linux提供的fork调用的写时复制特性.