详谈Linux写时拷贝技术(copy-on-write)必看篇
COW技术初窥
在linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,linux中引入了“写时复制”技术,也就是只有进程空间的各段的内容要发生变化时,才将父进程的内容复制一份给子进程。
那么子进程的物理空间没有代码,怎么去取指令执行exec系统调用呢??
在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,其对应的物理空间是一个。当父子进程中有更改相应段的行为发生时,再为子进程相应的段分配物理空间。如果不是因为exec,内核会给子进程的数据段、堆栈段分配相应的物理空间(至此两者都有各自的进程空间,互不影响),而代码段继续共享父进程的物理空间(两者的代码完全相同)。而如果是因为exec,由于两者执行的代码不同,子进程的代码段也会分配单独的物理空间。
在网上看到的还有个细节问题是:fork之后内核会将子进程排在队列的前面,以让子进程先执行,以免父进程执行导致写时复制,而后子进程执行exec系统调用,因无意义的复制而造成效率的下降。
COW详述
现在有一个父进程P1,这是一个主体,那么它是有灵魂也是有身体的。现在在其虚拟地址空间(有相应的数据结构表示)上有:正文段,数据段,堆,栈这四个部分,相应地,内核要为这四个部分分配给自的物理块。即正文段块、数据段块、堆块、栈块。至于如何分配,这是内核去做的事,在此不详述。
1. 现在P1用fork()函数为进程创建一个子进程P2
内核:
(1) 复制P1的正文段,数据段,堆,栈这四个部分,注意是其内容相同。
(2) 为这四个部分分配物理块,P2的:正文段(为P1的正文段的物理块,其实就是不为P2分配正文段块,让P2的正文段指向P1的正文段块),数据段(P2自己的数据段块,为其分配对应的块),堆(P2自己的堆块),栈(P2自己的栈块)。如下图所示,同左到右大的方向箭头表示复制内容:
2. 写时复制技术
写时复制技术:内核只为新生成的子进程创建虚拟空间结构,它们复制于父进程的虚拟空间结构,但是不为这些段分配物理内存,它们共享父进程的物理空间,当父子进程中有更改相应的段的行为发生时,再为子进程相应的段分配物理空间。
3. vfork
vfork的做法更加简单粗暴,内核连子进程的虚拟地址空间也不创建了,直接共享了父进程的虚拟空间,当然了,这种做法就顺水推舟的共享了父进程的物理空间
总结
传统的fork()系统调用直接把所有的资源复制给新创建的进程。这种实现过于简单并且效率低下,因为它拷贝的数据也许并不共享,更糟的情况是,如果新进程打算立即执行一个新的映像,那么所有的拷贝将是无用功。
Linux的fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种可以推迟甚至免除拷贝数据的技术。内核此时并不复制整个地址空间,而是让父进程和子进程共享一个拷贝。只有在需要写入的时候,数据才会复制,从而使各个进程拥有各自的拷贝。也就是说,资源的复制只有在需要写入的时候才进行,在此之前,只是以只读方式共享。这种技术使地址空间的页的拷贝被推迟到实际发生写入的时候。
在页根本不会被写入的情况下,举例来说,fork()之后立即调用exec(),它们就无需复制了,fork()的实际开销就是复制父进程的页表以及给子进程创建唯一的进程描述符。在一般情况下,进程创建后都会马上运行一个可执行的文件,这种优化可以避免拷贝大量根本不会使用的数据(地址空间常常包含数十兆的数据)。由于Unix强调进程快速执行的能力,所以这个优化是很重要的,注:Linux COW和exec没有必然联系
以上这篇详谈Linux写时拷贝技术(copy-on-write)必看篇就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。
相关推荐
-
Oracle Linux 6.8安装 mysql 5.7.17的详细教程
安装MySQL 5.7.17的方法如下所示: 1.下载 http://www.codeyyy.com/linux/149-150-153.html 2.上传解压 tar -xvf mysql-5.7.17-linux-glibc2.5-x86_64.tar.gz 3.新建mysql目录 mkdir -p /usr/local/mysql/data mv mysql-5.7.17-linux-glibc2.5-x86_64/* /usr/local/mysql/ 4.添加用户组 groupadd
-
Linux C中多线程与volatile变量
Linux C中多线程与volatile变量 volatile 修饰的变量表示改变量的值是易变的,编译器不对其进行优化,访问该变量的时候不会从寄存器读取, 而是直接从内存读取变量. 在多线程环境下,每个线程都有一个独立的寄存器,用于保存当前执行的指令.假设我们定义了一个全局变量,每个线程都会访问这个全局变量,这时候线程的寄存器可能会存储全量变量的当前值用于后续的访问.当某个线程修改了全局变量的值时,系统会立即更新该线程寄存器中对应的值,其他线程并不知道这个全局变量已经修改,可能还是从寄存器中获取
-
Linux编程之ICMP洪水攻击
我的上一篇文章<Linux编程之PING的实现>里使用ICMP协议实现了PING的程序,ICMP除了实现这么一个PING程序,还有哪些不为人知或者好玩的用途?这里我将介绍ICMP另一个很有名的黑科技:ICMP洪水攻击. ICMP洪水攻击属于大名鼎鼎的DOS(Denial of Service)攻击的一种,一种是黑客们喜欢的攻击手段,这里本着加深自己对ICMP的理解的目的,也试着基于ICMP写一段ICMP的洪水攻击小程序. 洪水攻击(FLOOD ATTACK)指的是利用计算机网络技术向目的主机发
-
Linux C中sockaddr和sockaddr_in的区别
Linux C中sockaddr和sockaddr_in的区别 struct sockaddr和struct sockaddr_in这两个结构体用来处理网络通信的地址. 在各种系统调用或者函数中,只要和网络地址打交道,就得用到这两个结构体. 网络中的地址包含3个方面的属性: 1 地址类型: ipv4还是ipv6 2 ip地址 3 端口 相应的,头文件有如下定义: include <netinet/in.h> struct sockaddr { unsigned short sa_family;
-
linux下tomcat常用操作
假设tomcat安装在/usr/local/tomcat7 启动tomcat cd /usr/local/tomcat7/bin ./startup.sh 查看启动状态 ps -ef|grep java root 3729 1729 6 09:23 pts/2 00:00:03 /usr/lib/jvm/java-8-openjdk-i386//bin/java -Djava.util.logging.config.file=/usr/local/tomcat7/conf/logging.pro
-
NetCore1.1+Linux部署初体验
NetCore1.1+Linux部署初体验 1.环境准备 Centaos7+Win10 虚拟机 Win10安装VS2017 注意勾选下.Net Core 3.Centaos安装netcore 1.1参见https://www.microsoft.com/net/core sudo yum install libunwind libicu curl -sSL -o dotnet.tar.gz https://go.microsoft.com/fwlink/?linkid=848821 sudo m
-
Linux系统中利用node.js提取Word(doc/docx)及PDF文本的内容
前言 想要做全文搜索引擎,则需要将word/pdf等文档内容提取出来.对于pdf有xpdf等一些开源方案. 但Word文档的情况则会复杂一些. 提取PDF文本内容 XPDF是一个免费开源的软件,用于显示PDF文件,并可将pdf转换成文字图片等,同样支持Windows版.在Debian Linux上安装非常简单: apt-get install xpdf 我们这里只使用pdftotext这个功能,直接输入可查看帮助: root@raspberrypi:/var/www# pdftotext pdf
-
详解Linux系统中网卡MAC地址克隆方法
怎么临时性地改变 MAC 地址? 你可以在 Linux 运行的时候改变 MAC 地址.需要注意的是当 MAC 地址转换的那一会时间,你的网络会掉线.当电脑重启时 MAC 地址又会变回原来的.下面介绍几种方法来改变你的 MAC 地址. 方法一:iproute2 $sudo ip link set dev eth0 down $sudo ip link set dev eth0 address 00:00:00:00:00:01 $sudo ip link set dev eth0 up 方法二:m
-
详谈Linux写时拷贝技术(copy-on-write)必看篇
COW技术初窥 在linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,linux中引入了"写时复制"技术,也就是只有进程空间的各段的内容要发生变化时,才将父进程的内容复制一份给子进程. 那么子进程的物理空间没有代码,怎么去取指令执行exec系统调用呢?? 在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段.数据段.堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,其对应的物理空间是一
-
浅谈linux下的一些常用函数的总结(必看篇)
1.exit()函数 exit(int n) 其实就是直接退出程序, 因为默认的标准程序入口为int main(int argc, char** argv),返回值是int型的. 一般在shell下面,运行一个程序,然后使用命令echo $?就能得到该程序的返回值,也就是退出值,在main()里面,你可以用return n,也能够直接用exit(n)来做.unix默认的习惯正确退出是返回0,错误返回非0. 重点:单独的进程是返回给操作系统的.如果是多进程,是返回给父进程的. 在父进程里面调用w
-
C++写时拷贝实现原理及实例解析
一.什么是写时拷贝 写入时复制是一种计算机程序设计领域的优化策略.其核心思想是,如果有多个调用者同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变. 这个过程对其他的调用者是透明的(transparently). 此作法的主要优点是如果调用者没有修改该资源,就不会有副本被建立,因此多个调用者只是读取操作是可以共享同一
-
深入理解C/C++中的写时拷贝
写时拷贝 何为写时拷贝? 前面我说过深拷贝浅拷贝,今天我们来探究一下写时拷贝.深拷贝是补充了浅拷贝的不足,写时拷贝其实也就是补充一点深拷贝的不足.其实写时拷贝的意思就是: 当你读取到这个空间的时候,并不会开辟出一个一模一样的空间出来给你,当你真正需要拷贝的时候,那么他就会开辟出空间给你.也就是拖延版的深拷贝. 写时拷贝技术是通过"引用计数"实现的,在分配空间的时候多分配4个字节,用来记录有多少个指针指向块空间,当有新的指针指向这块空间时,引用计数加一,当要释放这块空间时,引用计数减一(
-
c++中深浅拷贝以及写时拷贝的实现示例代码
本文主要给大家介绍了关于c++中深浅拷贝及写时拷贝实现的相关内容,分享出来供大家参考学习,下面话不多说,来一起看看详细的介绍: 一:浅拷贝&深拷贝 浅拷贝:在拷贝构造的时候,直接将原内容的地址交给要拷贝的类,两个类共同指向一片空间.但是存在很大的缺陷:①一旦对s2进行操作,s1的内容也会改变:②析构时先析构s2,再析构s1,但是由于s1,s2指向同一片空间,会导致一片空间的二次析构导致出错. 深拷贝:通过开辟和源空间大小相同的空间并将内容拷贝下来再进行操作.不论是否对s2进行操作,都会拷贝一片相
-
String类的写时拷贝实例
实例如下: #include<iostream> using namespace std; class String; ostream& operator<<(ostream &out, const String&s); //引用计数器类 class String_rep { friend class String; friend ostream& operator<<(ostream &out, const String&
-
C++深浅拷贝和写时拷贝图文详解
前言 之前我们在浅谈6个成员函数中有提到深浅拷贝的问题,现在再回首掏一把. 一.深浅拷贝哪家强? 先给出代码理一理 #define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> #include<assert.h> using namespace std; class String { friend ostream& operator<<(ostream &out, const String &s);
-
C++的深浅拷贝和写时拷贝你了解吗
目录 1.浅拷贝 2.深拷贝 3.引用计数+写时拷贝 总结 1.浅拷贝 浅拷贝:对于有申请空间的对象的类来说,是按照字节序依次拷贝过去的,并没有另外申请一块空间.因此,在调用析构函数的时候会造成同一块空间释放两次的情况,从而使程序崩溃. 如下实例: class string { public: string(const char* str) { //构造string类对象时,如果传递nullptr指针 //认为程序非法,此处断言下 assert(str); _str = new char[str
-
详谈PHP基础与JS操作的区别(必看篇)
嵌入页面方式 JS嵌入方式:<script></script> PHP嵌入方式:<?php ?>(常用) 输出语法 Javascript输出 1.alert("警告的内容") 2.prompt("提示的内容") 3.document.write()(页面输出内容) PHP输出 1.echo(常用)//可同时输出多个字符串 eg:echo $a,"hello"; 2.print //只能输出一个字符串 eg:pr
-
详谈Android中onTouch与onClick事件的关系(必看)
这几天遇到点关于Android的触摸事件相关的,还跟onClick有关,暂且记下: LinearLayout分别设置了onTouchListener,onClickListener,onLongClickListener及onTouchEvent回调 1.在屏幕上触摸之后基本的执行流程如下: onTouch,action=0 onTouchEvent,action=0 onTouch,action=2 onTouchEvent,action=2 onTouch,action=2 onTouchE
随机推荐
- thinkPHP3.2简单实现文件上传的方法
- C语言数据结构实现字符串分割的实例
- hta实现涂鸦效果代码
- dos变量定义和引用方法
- sql server几种Join的区别测试方法
- MongoDB聚合功能浅析
- Mybatis中 XML配置详解
- 解读ASP.NET 5 & MVC6系列教程(3):项目发布与部署
- jquery获取img的src值的简单实例
- Nginx反向代理一个80端口下配置多个微信项目详解
- python实现根据主机名字获得所有ip地址的方法
- 字符串和十六进制之间的转换方法实例
- PHP的简易冒泡法代码分享
- javascript下用ActiveXObject控件替换word书签,将内容导出到word后打印第1/2页
- 用Oracle并行查询发挥多CPU的威力
- 一个很酷的拖动层的js类,兼容IE及Firefox
- C# 无边框窗体之窗体移动实现代码
- c# 实现子窗口关闭父窗口也关闭的方法
- PHP 7.0新增加的特性介绍
- 详解Node 定时器