# COW写时复制

## Linux 下的 COW

`linux` 下的 `fork()` 函数会产生一个和父进程完全相同的子进程 (除了pid)

按照传统的做法，会直接将父进程的数据（内存）拷贝到子进程中，拷贝完之后，父进程和子进程之间的数据段和堆栈是相互独立的。

这也是进程和线程的区别之一，线程共享内存，而进程内存独立。

但很多时候复制给子进程的数据是用不着的，浪费性能和时间。

于是就有了 `Copy On Write` 这项技术，原理也很简单：

* `fork` 创建出的子进程，与父进程共享内存空间。子进程的地址空间指向父进程。但对这些内存空间只有读权限。
* 子进程写内存时，CPU硬件检测到内存页是只读的，于是触发页异常中断（page-fault），陷入 `kernel` 的一个中断例程。中断例程中，`kernel` 就会**把触发的异常的页复制一份**，于是父子进程各自持有独立的一份。

**好处**

* **减少**分配和复制大量资源时带来的**瞬间延时**。
* 减少**不必要的资源分配**。比如 fork 进程时，并不是所有的页面都需要复制，父进程的**代码段和只读数据段都不被允许修改，所以无需复制**。

**缺点**

* 如果在 `fork()` 之后，父子进程都还需要继续进行写操作，**那么会产生大量的分页错误 (页异常中断page-fault)**，这样就得不偿失。

## Redis 的 COW

`Redis` 在执行 `RDB` 持久化时，如果是采用 `BGSAVE/ BGREWRITEAOF` 的方式，那 `Redis` 会 `fork` 出一个子进程来读取数据，这个子进程采用的便是 `COW` ，子进程的地址空间指向父进程，这样就可以间接读到父进程数据。而不是复制一份数据到内存里，再持久化这份复制的数据。

## 文件系统的COW

对数据进行修改的时候，不会直接在原来的数据位置上进行操作，而是重新找个位置修改。这样的好处是一旦系统突然断电，重启之后不需要做 `Fsck (file system check)`。好处就是能保证数据的完整性，掉电的话容易恢复。

比如说：要修改数据块A的内容，先把A读出来，写到B块里面去。如果这时候断电了，原来A的内容是还在的。
