中国电子商务中心官网,青岛seo整站优化公司,湖南网页制作公司,旅游网站建设的利益写时复制技术(Copy on Write)是比较常用的一种技术#xff0c;它的主要目的是延迟减少以及延迟内存的分配#xff0c;增加执行效率#xff0c;只有在真正进行写操作的过程中才会真正分配物理资源。同时#xff0c;也可以保护数据在系统崩溃时出现的丢失。比如#xff0c;我…        写时复制技术(Copy on Write)是比较常用的一种技术它的主要目的是延迟减少以及延迟内存的分配增加执行效率只有在真正进行写操作的过程中才会真正分配物理资源。同时也可以保护数据在系统崩溃时出现的丢失。比如我们在进行文件修改时文件系统会首先将待修改数据放到另外一个位置然后进行操作。 看下维基百科的定义 写入时复制是一种计算机程序设计领域的优化策略。其核心思想是如果有多个调用者同时请求相同资源如内存或磁盘上的数据存储他们会共同获取相同的指针指向相同的资源直到某个调用者试图修改资源的内容时系统才会真正复制一份专用副本给该调用者而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的。此作法主要的优点是如果调用者没有修改该资源就不会有副本被建立因此多个调用者只是读取操作时可以共享同一份资源。  本文简单介绍其在操作系统以及编程语言中的实际使用情况。 
1、Linux操作系统 在linux系统中当我们要fork子进程的时侯就会采用COW的思想。即for一个子进程时侯并不是直接再重新分配一段物理内存给子进程而是子进程和父进程共用一段物理内存空间此时父进程和子进程都是只读内存。若子进程或者父进程要进程写操作再为其分配新的物理内存。 
具体原理是 fork()之后kernel把父进程中所有的内存页的权限都设为read-only然后子进程的地址空间指向父进程。当父子进程都只读内存时相安无事。当其中某个进程写内存时CPU硬件检测到内存页是read-only的于是触发页异常中断page-fault陷入kernel的一个中断例程。中断例程中kernel就会把触发的异常的页复制一份 于是父子进程各自持有独立的一份。 linux另外一个要介绍的是在RCU中的应用。 RCU全称时Read-copy-update是在linux2.6中引入的。当只是读时不需要加锁当进行写操作时会拷贝一份副本然后在合适的时候会将执行旧数据的指针更新为执行新数据。 相比于读写锁RCU最大的变化是进行写操作时读锁不需要被阻塞。此外就是其修改对于其他任务来说可能不是立即可见的有滞后性。因此对于数据具有敏感性需要实时读到最新的场景RCU是不合适的。另外RCU由于需要进行副本拷贝还要进行删除旧数据等一系列操作所以其写锁的开销成本较大。因此RCU在写操作越少的情况其性能就越好。 2、PHP PHP 在管理内存方面有一个机制叫写时复制COWCopy On Write保证了变量间复制值不浪费内存当一个变量的值复制到另一个变量时PHP 没有为复制值使用更多的内存相反它会更新符号表来说明两个变量拥有相同的内存块所以当执行下面的代码时并没有创建一个新的数组。只有在对应的引用指向的变量值发生变化时才会申请新空间。 
3、Java Java中有几种支持CopyOnWrite的容器CopyOnWriteArrayList和CopyOnWriteArraySet.其主要用于并发的场景是线程安全的但性能一般因为在添加元素时会复制一个array并加锁向其加入元素。下面是添加元素的源码 
public boolean add(E e) {final ReentrantLock lock  this.lock;lock.lock();try {Object[] elements  getArray();int len  elements.length;//复制一个新数组Object[] newElements  Arrays.copyOf(elements, len  1);newElements[len]  e;setArray(newElements);return true;} finally {lock.unlock();}
} 也就是说上面的容器还是比较适合读多写少的场景。因为写时复制的过程中会同时占用量份内存可能会频繁引起Java虚拟机的GC操作。此外它只能满足最终一致性并不能保证实时的一致性。相反Java的读写锁中读写是完全互斥的能实现强一致性。 4、Redis的Copy On write 当我们使用BGSAVE命令进行持久化的时候充分利用了Linux的写时复制机制。bgsave执行时redis会fork出一个子进程子进程和父进程共用一份内存当只有读时互不影响。 如果此时主进程有被修改的数据则被修改的数据对应的页才会进行复制随后会被子进程写入到RDB文件中。