You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

写入时复制Copy-on-write简称COW是一种计算机程序设计领域的优化策略。其核心思想是如果有多个调用者callers同时要求相同资源如内存或磁盘上的数据存储他们会共同获取相同的指针指向相同的资源直到某个调用者试图修改资源的内容时系统才会真正复制一份专用副本private copy给该调用者而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的transparently。此作法主要的优点是如果调用者没有修改该资源就不会有副本private copy被创建因此多个调用者只是读取操作时可以共享同一份资源。

1.使用场景

1.1 在文件系统中的应用

数据的备份或者复制至少处于硬件(硬盘)和操作系统两个层级。硬件备份一般使用RAID0-10的方案保护硬盘中的数据安全操作系统中则使用Snapshot(快照)技术来维持数据的安全和有效。人们一直采用数据复制、备份、恢复等技术来保护重要的数据信 息,定期对数据进行备份或复制。由于数据备份过程会影响应用性能,并 且非常耗时,因此数据备份通常被安排在系统负载较轻时进行(如夜 间)。另外为了节省存储空间通常结合全量和增量备份技术。为了解决性能和持续运行的问题引入了SnapshotSnapshot的实现又主要分为split mirror、changed block和current三大类具体实现方式中会有部分依赖COW技术。

1.2 软件和web系统中的应用

传统方式下,fork()函数在创建子进程时直接把所有资源复制给子进程正文段块数据段块堆块栈块。这种实现方式简单但是效率低下而且复制的资源可能对子进程毫无用处。linux为了降低创建子进程的成本改进fork()实现方式使用COW技术创建子进程。当父进程创建子进程时内核只为子进程创建虚拟空间父子两个进程使用的是相同的物理空间。只有父子进程发生更改时才会为子进程分配独立的物理空间。 !3669053-3b340bc054bdb1e0.png

上图展示从P1进程创建子进程P2时的物理空间使用状况。通过COW技术fork()延迟了数据拷贝,根据子进程的实际操作最终可能完全避免数据复制,如:子进程创建后运行一个与当前数据无关的可执行文件。

Redis中的COW

Redis的快照就是使用fork()函数创建子进程,由子进程读取数据并持久化到磁盘完成。

JDK中的COW

CopyOnWriteArrayListCopyOnWriteArraySet都是使用在读多写少且数据总量不大的场景下在保证多线程写的原子性的同时又避免了读的冲突和竞争使用迭代器的时候也绝对不会抛出ConcurrentModificationException。