Copy-on-Write:父子进程为什么可以先共享同一份内存?
TL;DR
写时复制让多个使用者先共享只读页面,直到某一方真的写入时才创建私有副本,是 fork、快照和容器层常用的延迟复制策略。
写时复制让多个使用者先共享只读页面,直到某一方真的写入时才创建私有副本,是 fork、快照和容器层常用的延迟复制策略。

Copy-on-Write(写时复制,COW)是一种很朴素却影响深远的优化:多个使用者先共享同一份数据,只有某个使用者真的要修改时,系统才为它复制一份私有版本。它把“可能会改”延迟到“确定要改”的那一刻。
Unix 创建子进程时经常利用这一点。fork 之后,父进程和子进程最初可以共同指向相同的物理页面;这些页面被标记为只读。只要双方都读取,内存无需复制;一旦某个进程写入,处理器触发缺页异常,操作系统分配新的页面,把原内容复制过去,再让写入者修改自己的副本。
这就像复印店只给全班发同一本参考资料:大家可以一起看原件,只有某位同学要在页边做笔记,店里才复印那一页。对大量读取、少量修改的数据,COW 能明显节省内存和启动时间,也被用于快照、容器层、文件系统和持久化数据结构。
代价是第一次写入会承担缺页、分配和复制延迟,写入热点还可能让共享页面迅速裂变。大规模 fork 后如果父子进程都要修改大量内存,COW 的峰值内存可能突然上升;如果应用误以为“共享就永远省内存”,也会在写时付出意外成本。
COW 的设计重点是权限和引用计数:共享期间阻止直接写入,写故障发生后判断页面是否仍被多人使用,并为写者建立独立版本。它把资源共享和版本隔离结合起来,是操作系统里“先共享、后分叉”这一普遍思想的典型。
快照系统也会利用同样的思想:先把旧版本当作只读基线,新的写入只记录发生变化的块。这样可以快速创建看似完整的副本,但长期累积的写入层会带来碎片、合并和空间回收成本。COW 因而是一种延迟成本的策略,不是让复制完全消失。
在数据库和对象存储中,COW 还常常与版本号、校验和、垃圾回收配合使用。读者可以继续引用旧版本,写者发布新版本后再清理无人引用的旧数据。这样既获得了快照式读取,也把空间回收从写入路径移到了后台任务。
资料来源:Mel Gorman:Understanding the Linux Virtual Memory Manager



