Skip to content

Latest commit

 

History

History
41 lines (18 loc) · 2.76 KB

copy-on-write.md

File metadata and controls

41 lines (18 loc) · 2.76 KB

Copy on Write

Copy on Write(写时复制)的核心思想是,如果有多个调用者(callers)同时要求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这个过程对所有调用者是透明的。

fork、exec与COW

Linux下有 fork 和 exec 函数,其中 exec 是一组函数,用于 装载一个新的程序(可执行映像)覆盖当前进程内存空间中的映像,从而执行不同的任务。

fork函数:创建一个与父进程相同的子进程,相同是是指:子进程的 代码段、数据段、堆栈都与父进程,也就是说,两者的虚拟空间不同,其对应的物理空间是一个。

fork函数刚创建出子进程时,父子进程共享内存空间,当父进程或子进程要对内存空间进行 写操作(修改内存空间中的数据)时,再复制内存数据。

exec函数在执行时会直接替换掉当前进程的地址空间。fork出来的子进程与父进程有相同的功能(具有相同的代码段),exec函数会装载新的程序,实现新的功能。

总结:

  1. fork之后,父子进程共享内存中相同的物理空间(但是虚拟地址不同), 子进程的代码段、数据段、堆栈都是指向父进程的物理空间。

  2. 父进程或子进程要对内存空间进行 写操作(修改内存空间中的数据)时,再为子进程分配 物理空间。

  3. exec函数修改的是程序的 代码段,会引起代码段的复制,如果没用调用 exec 函数,父子进程功能相同,只会重新分配数据段、堆栈的地址空间。

COW 原理

  1. 调用 fork函数之后,内核将父进程所有的内存也都设为 read only

  2. a. 当父进程或者子进程要 读 内存时,可以正常进行;

    b. 当父进程或者子进程要 写 内存时,监测到此页面是只读的,触发一个页异常中断(page-fault),中断例程中,内核就会把触发的异常的页复制一份;

可见,COW可以减少不必要的资源复制,加快fork函数创建进程的速度。但是,如果父子进程要进行很多次写操作时,会引起大量的 页中断,需要多次陷入内核,降低程序运行效率。

在redis持久化中,BGSAVE命令或BGREWRITEAOF命令,都会fork出一个子进程来读写数据进行持久化。此时,要减少父进程的写操作,如设置此时hash表不能rehash(rehash有大量的写操作)。 同时,fork出子进程进行rehash时,要减少父进程的写操作,如将负载因子阈值提高。