Linux-Copy On Write写时复制机制初探

简介: Linux-Copy On Write写时复制机制初探

20200507151541785.jpg


生猛干货

从系统安装到程序员必备的Linux技能,还原真实工作场景,手把手带你实战演练


20210304160434749.png


COW概述


来看下 https://en.wikipedia.org/wiki/Copy-on-write的说明


Copy-on-write (COW), sometimes referred to as implicit sharing[1] or shadowing,[2] is a resource-management technique used in computer programming to efficiently implement a “duplicate” or “copy” operation on modifiable resources.[3] If a resource is duplicated but not modified, it is not necessary to create a new resource; the resource can be shared between the copy and the original. Modifications must still create a copy, hence the technique: the copy operation is deferred to the first write. By sharing resources in this way, it is possible to significantly reduce the resource consumption of unmodified copies, while adding a small overhead to resource-modifying operations.


写入时复制(COW),有时也称为隐式共享,是一种计算机管理中用来有效地对可修改资源执行“复制”操作的资源管理技术。


如果资源重复但未修改,则无需创建新资源,资源可以在副本和原始副本之间共享。


修改仍然必须创建一个副本,因此使用COW,可以将复制操作推迟到第一次写入。


通过以这种方式共享资源,可以显着减少未修改副本的资源消耗,当然了资源修改操作的时候也会增加少量开销。



20200508105427769.jpg


简单来说 COW 写时复制是提高资源使用效率的一种手段, 在内存管理(进程的 fork),数据存储( 比如 Docker 的 AUFS 文件系统),软件开发(Java的Copy On Write容器)、高可用HA软件中广泛使用。


*Unix


在传统的Unix环境下,有两个基本的操作用于创建和修改进程:


函数fork( )用来创建一个新的进程,该进程几乎是当前进程的一个完全拷贝


函数族exec( )用来启动另外的进程以取代当前运行的进程(函数族exec( )是一组函数的统称, 它包括了execl()、execlp()、execv()、execle()、execve()、execvp()等)


fork


fork是类Unix操作系统上创建进程的主要方法,fork用于创建子进程。

新的进程要通过老的进程复制自身得到,Linux下init进程是所有进程的父 。 Linux的进程都通过init进程或init的子进程fork(vfork)出来的

#include <unistd.h>  
#include <stdio.h>  
int main ()   
{   
    pid_t fpid; //fpid表示fork函数返回的值  
    int count=0;
  // 调用fork,创建出子进程  
    fpid=fork();
  // 所以下面的代码有两个进程执行!
    if (fpid < 0)   
        printf("创建进程失败!/n");   
    else if (fpid == 0) {  
        printf("我是子进程,由父进程fork出来/n");   
        count++;  
    }  
    else {  
        printf("我是父进程/n");   
        count++;  
    }  
    printf("统计结果是: %d/n",count);  
    return 0;  
}  

输出结果

我是子进程,由父进程fork出来
统计结果是: 1
我是父进程
统计结果是: 1



fork 函数会有两次返回 1) 将子进程的PID返回给父进程,2) 0返回给子进程。(如果小于0,则说明创建子进程失败)。


当前进程调用fork(),会创建一个跟当前进程完全相同的子进程(除了pid),所以子进程同样是会执行fork()之后的代码。


故: 父进程在执行if代码块的时候,fpid变量的值是子进程的pid,子进程在执行if代码块的时候,fpid变量的值是0



函数族exec( )


在Linux中要使用exec函数族。系统调用execve()对当前进程进行替换,替换者为一个指定的程序,其参数包括文件名(filename)、参数列表(argv)以及环境变量(envp)。


exec函数族不止一个,但它们大致相同,在 Linux中,它们分别是:execl,execlp,execle,execv,execve和execvp。


一个进程一旦调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序了。


20200508153550166.png


为什么有了COW?


早期的 Unix 在实现 fork 系统调用时,并没有使用该技术,创建新进程的开销很大。


出于效率考虑,Copy On Write 技术引入到进程中,fork 之后的父进程和子进程完全共享数据段、代码段、堆和栈等的完全副本。


Linux在使用fork()函数进程创建时,传统fork()的做法是系统把所有的资源复制给新创建的进程,这种方式不仅单一,而且效率低下。因为所拷贝的数据或别的资源可能是可以共享的。现在Linux的fork()使用写时拷贝页来实现新进程的创建,它是一种可推迟甚至避免数据拷贝的技术,刚开始时内核并不会复制整个地址空间,而是让父子进程共享地址空间,只有在写时才复制地址空间,使得父子进程都拥有独立的地址空间,即资源的复制是在只有需要写入时才会发生,因此而称之为Copy on Write(COW)。


在此之前都是以读的方式去和父进程共享资源,这样,在页根本不会被写入的场景下,fork()立即执行exec(),无需对地址空间进行复制,fork()的实际开销就是复制父进程的一个页表和为子进程创建一个进程描述符,也就是说只有当进程空间中各段的内存内容发生变化时,父进程才将其内容复制一份传给子进程,大大提高了效率。


通俗来说 fork创建出的子进程,与父进程共享内存空间。 如果子进程不对内存空间进行写入操作的话,内存空间中的数据并不会复制给子进程,这样创建子进程的速度就很快 ,因为不用复制,直接引用父进程的物理空间 ,并且如果在fork函数返回之后,子进程第一时间exec一个新的可执行映像,那么也不会浪费时间和内存空间了 。


COW 原理


fork()之后,kernel把父进程中所有的内存页的权限都设为read-only,然后子进程的地址空间指向父进程。当父子进程都只读内存时,相安无事。当其中某个进程写内存时,CPU硬件检测到内存页是read-only的,于是触发页异常中断(page-fault),陷入kernel的一个中断例程。中断例程中,kernel就会把触发的异常的页复制一份,于是父子进程各自持有独立的一份。


COW的优缺点


优点


COW技术可减少分配和复制大量资源时带来的瞬间延时。

COW技术可减少不必要的资源分配。比如fork进程时,并不是所有的页面都需要复制,父进程的代码段和只读数据段都不被允许修改,所以无需复制。


缺点


如果在fork()之后,父子进程都还需要继续进行写操作,那么会产生大量的分页错误(页异常中断page-fault),这样就得不偿失。


小结



fork出的子进程共享父进程的物理空间,当父子进程有内存写入操作时,read-only内存页发生中断,将触发的异常的内存页复制一份(其余的页还是共享父进程的)。


fork出的子进程功能实现和父进程是一样的。如果有需要, 会调用exec()把当前进程映像替换成新的进程文件,完成自定义的功能。


参考:

维基百科-Copy-on-write

COW奶牛!Copy On Write机制了解一下


搞定Linux核心技术


https://artisan.blog.csdn.net/article/details/105973320?spm=1001.2014.3001.5502


相关文章
|
5月前
|
存储 Linux C语言
Linux:冯·诺依曼结构 & OS管理机制
Linux:冯·诺依曼结构 & OS管理机制
150 0
|
1月前
|
存储 监控 安全
探究Linux操作系统的进程管理机制及其优化策略
本文旨在深入探讨Linux操作系统中的进程管理机制,包括进程调度、内存管理以及I/O管理等核心内容。通过对这些关键组件的分析,我们将揭示它们如何共同工作以提供稳定、高效的计算环境,并讨论可能的优化策略。
32 0
|
2月前
|
存储 缓存 编译器
Linux源码阅读笔记06-RCU机制和内存优化屏障
Linux源码阅读笔记06-RCU机制和内存优化屏障
|
3月前
|
缓存 监控 关系型数据库
深入理解Linux操作系统的内存管理机制
【7月更文挑战第11天】在数字时代的浪潮中,Linux操作系统凭借其强大的功能和灵活性,成为了服务器、云计算以及嵌入式系统等领域的首选平台。内存管理作为操作系统的核心组成部分,对于系统的性能和稳定性有着至关重要的影响。本文将深入探讨Linux内存管理的基本原理、关键技术以及性能优化策略,旨在为读者提供一个全面而深入的理解视角,帮助开发者和系统管理员更好地优化和管理Linux系统。
|
3月前
|
缓存 网络协议 算法
【Linux系统编程】深入剖析:四大IO模型机制与应用(阻塞、非阻塞、多路复用、信号驱动IO 全解读)
在Linux环境下,主要存在四种IO模型,它们分别是阻塞IO(Blocking IO)、非阻塞IO(Non-blocking IO)、IO多路复用(I/O Multiplexing)和异步IO(Asynchronous IO)。下面我将逐一介绍这些模型的定义:
153 1
|
4月前
|
存储 缓存 Linux
Linux VFS机制详解
Linux VFS机制详解
124 1
|
4月前
|
Linux
Linux异步io机制 io_uring
Linux异步io机制 io_uring
60 1
|
5月前
|
Linux 数据库
linux守护进程介绍 | Linux的热拔插UDEV机制
linux守护进程介绍 | Linux的热拔插UDEV机制
linux守护进程介绍 | Linux的热拔插UDEV机制
|
3月前
|
NoSQL 算法 Linux
【内附完整redis配置文件】linux服务器命令设置redis最大限制内存大小,设置redis内存回收机制,redis有哪些回收机制
【内附完整redis配置文件】linux服务器命令设置redis最大限制内存大小,设置redis内存回收机制,redis有哪些回收机制
79 0
|
5月前
|
安全 Linux 调度
xenomai+linux双内核下的时钟管理机制
clock是操作系统正常运行的发动机,系统利用时钟中断维持系统时间、促使任务调度,以保证所有进程共享CPU资源;可以说,“时钟中断”是整个操作系统的脉搏。那你是否好奇xenomai cobalt内核和Linux内核双内核共存的情况下,时间子系统是如何工作的?一个硬件时钟如何为两个操作系统提供服务的?本文将揭开xenomai双核系统时间机制
112 0
xenomai+linux双内核下的时钟管理机制