1、简介
将复制操作推迟到第一次写入时进行:在创建一个新副本时,不会立即复制资源,而是共享原始副本的资源;当修改时再执行复制操作。
通过这种方式共享资源,可以大幅减少内存消耗和复制开销,同时实现高效的资源复制。
优点:
- 内存利用率高:
- 在初始化时,COW 技术可以让多个进程共享同一份内存页面,减少内存占用。
- 只有在某个进程需要修改页面时,才会复制出新的页面,从而提高内存利用率。
- 性能提升:
- 在创建新进程时,COW 技术可以快速完成页面复制,避免了全量拷贝的开销。
- 这对于需要频繁创建子进程的场景(如 Redis 的数据持久化)非常有利。
- 数据一致性:
- COW 技术可以确保每个进程都拥有一致的数据视图,避免了数据竞争问题。
- 这对于多进程共享数据的场景很有帮助。
缺点:
- 内存碎片问题:
- 频繁的页面复制可能会导致内存碎片,降低内存使用效率。
- 这需要操作系统提供相应的内存管理策略来缓解。
- 不适用于高并发修改场景:
- 如果多个进程同时修改同一个页面,COW 技术就无法提供数据一致性保证。
- 这种场景下需要采用其他的并发控制机制。
2、背景
在传统的内存管理机制中,当通过 fork() 来创建一个子进程时,操作系统需要将父进程虚拟内存空间中的大部分内容全部复制到子进程中(主要是数据段、堆、栈;代码段共享)。这个操作不仅非常耗时,而且会浪费大量物理内存。特别是如果程序在进程复制后立刻使用 exec 加载新程序,那么负面效应会更严重,相当于之前进行的复制操作是完全多余的。
因此引入了写时复制技术。内核不会复制进程的整个地址空间,而是只复制其页表,fork 之后的父子进程的地址空间指向同样的物理内存页。当一个进程试图写入共享区域的某个页面,那么就会为这个进程创建该页面的一个新副本。
3、工作原理
- 当父进程调用fork()创建子进程时,内核会将父进程的所有内存页都标记为只读(即共享页面),并增加每个页面的引用计数。在这个过程中,父子进程共享同一份内存页面,可以大幅减少内存占用。
- 一旦其中一个进程(父进程或子进程)尝试写入某个内存页,就会触发一个保护故障(缺页异常),此时会陷入内核,内核将拦截这个写入操作,检查该页面的引用数:
- 如果引用数大于 1,则会创建该页面的副本,并将引用数减 1,同时恢复这个页面的可写权限,然后重新执行这个写操作;
- 如果页面的引用数只有 1,也就是说该页面只被当前进程引用,那么内核就可以跳过分配新页面的步骤,直接修改该页面,将其标记为可写。
这种分配过程对于进程来说是透明的,即进程无需关心内存页面的引用计数和复制过程,能够确保一个进程的内存更改在另一进程中不可见。
在一般情况下,当子进程通过写时复制机制创建了自己的内存页面副本后,这个副本会一直与父进程的页面保持不一致,直到该子进程退出或被杀死。
如果需要让子进程的页面修改内容"回写"到父进程的页面中,可以使用以下系统调用:
msync()
系统调用:
msync()
可以用来同步内存映射文件的内容。- 子进程可以在修改页面后,调用
msync()
将修改的内容写回到内存映射的文件中。 - 之后父进程就可以从映射文件中读取到子进程的修改内容。
madvise()
系统调用:
madvise()
可以用来提供内存使用的建议信息给操作系统。- 子进程可以在修改页面后,调用
madvise()
并指定MADV_DONTNEED
选项,告知操作系统可以丢弃该页面的内容。 - 这样操作系统就会将子进程修改过的页面内容写回到父进程的页表指向的原始页面中。
不过这种做法与 COW 的数据隔离特性相反,需要根据实际需求来权衡使用。
4、应用
4.1 Redis
- 数据持久化:
- Redis 支持 RDB 和 AOF 两种数据持久化方式。
- 在执行
SAVE
或BGSAVE
命令时,Redis 会 fork 出一个子进程来执行持久化操作。 - 这时 Redis 主进程和子进程会共享同一份内存页面,直到子进程需要写入数据时才会复制页面(Copy-On-Write)。
- 数据复制(主从复制):
- Redis 支持主从复制,从服务器会 fork 出一个子进程来同步主服务器的数据。
- 在同步过程中,主从服务器也会共享内存页面,直到从服务器需要写入数据时才会复制页面。
- 集群伸缩:
- Redis 集群在增加或删除节点时,也会用到 COW 技术来减少内存开销。
- 当增加节点时,新节点会 fork 出一个子进程来复制其他节点的数据,在复制过程中利用 COW 技术。
4.2 文件拷贝
当需要拷贝一个大文件时,操作系统也会使用COW技术,拷贝操作会创建一个新的文件句柄,并将原文件的数据页面映射给新文件,而不是直接复制整个文件内容。只有当其中一个文件被修改时,操作系统才会为其创建一个副本。
4.3 快照和克隆
在文件系统中,COW技术可用于快照和克隆功能,当创建快照或克隆时,操作系统仅会复制元数据,而不会复制整个文件系统,只有当某个文件被修改时,才会为该文件创建一个新的数据块。