初识进程的地址空间、页表

一、🌟问题引入

🚩代码一:

   #include<stdio.h>
   #include<unistd.h>
   int g_val=100;
   
   int main()
   {
     pid_t id=fork();
     if(id==0)
     {
      //子进程
      while(1)
      {
        printf("I am a child  pid:%d ppid:%d  g_val:%d\n",getpid(),getppid(),g_val);
        sleep(1);
      }
    }
     else
    {
  
      while(1)
      {
        printf("I am a parent  pid:%d ppid:%d  g_val:%d\n",getpid(),getppid(),g_val);
        sleep(1);
      }

     }
    return 0;                                                                                                                                                                                  
  }

可以看出子进程与父进程中g_val的地址值是一样的,这是因为子进程继承了父进程的代码和数据,两者共享数据

🚩代码二:(子进程修改数据)

   #include<stdio.h>
   #include<unistd.h>
   int g_val=100;
   
   int main()
   {
     pid_t id=fork();
     if(id==0)
     {
      //子进程
      int cnt=5;
      while(cnt)
      {
        printf("I am a child  pid:%d ppid:%d  g_val:%d &g_val:%p\n",getpid(),getppid(),g_val,&g_val);
        sleep(1);
        cnt--;
      }
      if(cnt==0)
      {
        g_val=0;
        printf("g_val changed: g_val:%d &g_val:%p\n",g_val,&g_val);
  
      while(1)
      {
        printf("I am a child  pid:%d ppid:%d  g_val:%d &g_val:%p\n",getpid(),getppid(),g_val,&g_val);
        sleep(1);
      }

      }
    }                                                                                                                                                                                            
    else
   {
      while(1)
      {
        printf("I am a parent  pid:%d ppid:%d  g_val:%d &g_val:%p\n",getpid(),getppid(),g_val,&g_val);
        sleep(1);
      }
  
    }
    return 0;
  }

我们发现,父进程与子进程中g_val的值不一样,这可以理解,因为进程之间具有独立性,但是为什么他们地址是一样的呢?

得出以下结论:

  • 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量
  • 但地址值是一样的,说明,该地址绝对不是物理地址
  • 在Linux地址下,这种地址叫做 虚拟地址

二、🌟地址空间

2.1 💬如何理解地址空间

进程 = 进程控制块(task_struct)+ 代码和数据

        操作系统维护进程不止通过进程控制块(task_struct),每个进程其实还存在一个地址空间,它将进程的代码和数据分成不同的区管理起来,地址从低到高有正文区初始化数据区未初始化数据区堆区共享区栈区命令行参数与环境变量区,但真正的数据并不保存在地址空间中,地址空间仅提供连续线性的一串地址,这种地址叫虚拟地址, 通过虚拟地址映射到数据真正存储的物理地址,我们在用C/C++语言所看到的地址,全部都是虚拟地址,物理地址用户一概看不到,由OS统一管理,操作在Linux操作系统中地址空间是用一个叫 mm_struct 的结构体维护起的

        虚拟地址映射到物理地址要通过页表,目前可以把他理解为保存着虚拟地址到物理地址映射关系的表

        

2.2 💬问题解释(写实拷贝)

        父进程创建子进程的时候,子进程会将父进程许多的内核数据结构都拷贝一份,其中就包括了页表,父进程在页表中保存了g_val的映射关系,所以子进程也可以访问到g_val,这就是父子进程中g_val的值与地址相同的原因。

        当子进程要修改g_val时,由于父子进程对g_val映射到相同的物理地址,父进程中的g_val也会随之修改,但是为了满足进程独立性的特点,操作系统会在物理内存中重新开辟一段新的空间,

并将g_val的值拷贝过来,这时子进程的页表就会重新映射物理地址,这时子进程修改g_val,父进程就不会收到影响了,这个操作全程由操作系统自主完成,称之为写实拷贝

ps:如果一个全局变量父子进程都不进行修改,两者是进行共享的,并不会直接让子进程拷贝一份,这时因为许多变量父子进程一般不会进行修改,但这些数据却很大,比如说环境变量等,直接拷贝一份会很浪费空间,所以当其中一方要修改时,才会进行拷贝,通过调整拷贝的时间顺序,达到节省空间的效果

2.3 💬地址空间的意义

1. 让无序变成有序,让进程以同意的视角看待物理内存,以及自己运行的各个区域

【解释】:

        一个进程的代码和数据在物理内存中的存储不一定是连续的,可能会根据数据类型的不同分别存储在物理内存的各个地方,此时进程要管理这些数据,就需要在task_struct中讲这些散乱的数据分别管理起来,当进程很多的时候,就会造成数据混乱,不利于操作系统的内存管理。

        而每个进程拥有自己独立的地址空间后,就不会被物理内存中的杂乱的数据影响了,管理数据只需要将虚拟地址通过页表映射到物理内存中即可

2. 进程模块与内存管理模块发生解耦

【解释】:

        当我们在写C语言程序时,比方说要使用堆空间,可以利用malloc函数开辟好,但是可能代码跑了很长时间后才会使用这段空间,那这段时间别的进程就无法利用这段空间了,会造成空间的浪费,有了虚拟地址和页表的概念,当进程需要开辟空间时,操作系统只需要将虚拟地址填入页表,但并不构建映射关系,当进程需要使用这段空间时,操作系统才会在物理内存开辟好空间,再构建映射关系,这样就可以大大提高空间的利用率。通过虚拟地址和页表构建映射关系等操作为进程的管理,在物理内存开辟空间等操作为内存管理,地址空间可以使两模块发生解耦,提高系统的资源利用

3. 拦截非法请求,保护操作系统

  【解释】:   

        当进程想访问一个地址的内容时,操作系统会先检查页表中是否存在该虚拟地址,如果不存在,就拦截这个请求,并报错提醒,防止其向物理内存修改数据,这就是为什么我们写程序有非法访问时程序会报错,而不是操作系统直接崩溃的原因

2.4 深入理解页表与写实拷贝

        其实页表并没有上述讲的这么简单,其内部还有许多寄存器和字段信息等,例如数据是否存在内存中、rwx权限等,我们可以举两个例子理解一下,本文只是初识地址空间,关于页表的更多信息后续会讲。

(1) 理解常量区修改

        我们在写程序时,对常量区的内容进行修改时程序会发生报错,那为什么修改别的区的内容是程序就不报错呢?这是由于页表中存在着对数据rwx权限判断的字段,操作系统会讲常量的数据权限修改为只读,当我们要修改常量区内容时,操作系统拿着虚拟地址在页表中找映射关系进行修改,发现该数据没有写权限,就会拦截这个请求,并报错,保护物理内存。

(2)系统是如何检测写实拷贝的

        当父进程创建子进程时,会将父子进程对数据的rwx权限仅保留读权限,当父子任意一方想要修改数据时,就会检测到错误,这时操作系统就会检测是否要发生写实拷贝

  (3) 如何理解fork函数返回两个返回值

        当fork( )函数运行完代码,会return一个返回值,pid_t id = fork() ,return的本质就是修改id

的值,此时就会发生写实拷贝,父子进程就会各自返回一个值

      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/483211.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

# Maven Bom 的使用

Maven Bom 的使用 文章目录 Maven Bom 的使用概述BOM特点优点缺点 MavenMaven 安装安装步骤settingx.ml常用仓库地址Idea 使用maven常见坑 SpringBoot 项目Bom使用案例项目结构主项目 zerocode-back-servezc-dependency&#xff08;第三方jar管理&#xff09;子模块zc-serve子模…

【保姆级教程】YOLOv8目标检测:训练自己的数据集

一、YOLOV8环境准备 1.1 下载安装最新的YOLOv8代码 仓库地址&#xff1a; https://github.com/ultralytics/ultralytics1.2 配置环境 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple二、数据准备 2.1 安装labelme标注软件 pip install label…

2024阿里云2核2G服务器租用价格99元和61元一年

阿里云2核2G服务器配置优惠价格61元一年和99元一年&#xff0c;61元是轻量应用服务器2核2G3M带宽、50G高效云盘&#xff1b;99元服务器是ECS云服务器经济型e实例ecs.e-c1m1.large&#xff0c;2核2G、3M固定带宽、40G ESSD entry系统盘&#xff0c;阿里云活动链接 aliyunfuwuqi.…

[STM32] Keil MDK 新建工程编译不通过(warning: #2803-D和Error: L6218E)解决方法备忘

按照野火的PDF教程的第4章&#xff1a;[野火]《RT-Thread 内核实现与应用开发实战—基于STM32》.pdf 新建 Keil MDK 工程&#xff0c;工程设置完成后点击编译按钮&#xff0c;编译不通过&#xff1a; RTE\Device\ARMCM3\startup_ARMCM3.c(75): warning: #2803-D: unrecognize…

JVM快速入门(1)JVM体系结构、运行时数据区、类加载器、线程共享和独享、分区、Java对象实例化

5.1 JVM体系结构 线程独占区-程序计数器&#xff08;Program Counter Register&#xff09; 程序计数器是一块较小的内存空间&#xff0c;它可以看做是当前线程所执行的字节码的行号指示器&#xff1b;在虚拟机的概念模型里&#xff0c;字节码解释器工作时就是通过改变这个计数…

C++:练习题

一、构造、析构顺序 C c; int main() {A a;B b;static D d;return 0; } //构造顺序&#xff1a;C A B D //析构顺序&#xff1a;~B ~A ~D ~C 二、拷贝构造次数 以下代码共调用多少次拷贝构造&#xff1f; Widget f(Widget u) //第一次&#xff1a;传值拷贝构造 {Widget v(u…

【QT+QGIS跨平台编译】之九十:【QGIS_Crashhandler+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、QGIS_Crashhandler介绍二、QGIS下载三、文件分析四、pro文件五、编译实践一、QGIS_Crashhandler介绍 QGIS_Crashhandler模块是QGIS中的一个重要组成部分,它提供了QGIS程序的错误崩溃处理与跟踪。 二、QGIS下载 QGIS网址: QGIS Source Download 获取最新版本的…

【Linux系统编程(进程编程)】进程的退出:父进程等待子进程的退出之僵尸进程与孤儿进程

文章目录 一、进程退出1.1、进程正常退出方式1.2、异常退出 二、父进程等待子进程退出&#xff08;一&#xff09;2.1、为什么要等待子进程退出2.2、&#xff08;1&#xff09;父进程等待子进程退出并收集子进程的退出状态如何等待wstatus空wstatus非空 2.3、&#xff08;2&…

数据背后的力量:揭秘中间件中的二分查找与树结构应用

平时写业务代码的时候很少写对应的算法&#xff0c;因为很少会在内存中存储大量数据&#xff0c;在需要比较大量数据的查找时&#xff0c;多会依赖的中间件&#xff0c;而中间件底层就应用了很多不同算法&#xff0c;尤其是树结构的查找存储算法&#xff0c;二分查找算法在树里…

状态管理@Prop、@Link装饰器

Prop Link 父子组件进行数据同步化 prop 单向同步 只支持string、number、boolean、enum类型 负组件对象类型&#xff0c;总组件是对象类型 不可以是数组、any 不允许子组件初始化 Link双向同步 父子类型一直&#xff1a;string、number、boolean、enum、object、class以及他们…

centos7 yum 安装mysql8.0.36

一、前置条件&#xff1a;CentOS Mini 安装需要先安装ifconfig 和 wget工具&#xff0c;参考步骤&#xff1a; 1.首先&#xff0c;让我们找出哪个包提供了ifconfig命令。要完成这项任务&#xff0c;输入以下命令&#xff1a; yum provides ifconfig 输出&#xff1a; [rootlo…

Vue3 + Django 前后端分离项目实现密码认证登录

1、功能需求 通常中小型前后端项目&#xff0c;对安全要求不高&#xff0c;也可以采用密码认证方案。如果只用django来实现非常简单。采用 Vue3 前后端分离架构&#xff0c;实现起来稍繁琐一点&#xff0c;好处是可以利用各种前端技术栈&#xff0c;如element-plus UI库来渲染…

Android Jetpack Compose基础之组件的帧渲染

Android Jetpack Compose基础之组件的帧渲染 组合布局LayoutModifier示例 LayoutCompsable示例 绘制CanvasDrawModifierDrawModifier-drawWithContent示例 DrawModifier-drawBehind源码示例 DrawModifier-drawWithCache源码示例 拓展Modifier.graphicsLayer Android View 系统&…

6-191 拓扑排序

一项工程由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其他子任务后才能执行。例如,下图表示了一项工程若干子任务之间的先后关系。 编写函数输出所有子任务的拓扑序列。 函数接口定义: Status Push_SeqStack(SeqStack &s, ElemType x)//入栈,x入到…

Polar 2024春季个人挑战赛 Jay17 WP

Polar 2024春季个人挑战赛 Rank&#xff1a;7 【WEB】机器人 开题 起手敏感文件robots.txt 【WEB】PHP反序列化初试 最简单的php反序列化 POC&#xff1a; <?php class Easy{public $name;public function __wakeup(){echo $this->name;} } class Evil{public $evi…

2、Jenkins持续集成-gitlab安装和源码上传

文章目录 1、Gitlab代码托管服务器安装2、源代码上传托管 环境&资源准备 统一采用VMware中安装CentOS7&#xff0c;安装教程&#xff0c;统一设置静态IP资源包都存在于我的资源里面 资源版本&位置 名称机器IP软件代码托管服务器192.168.2.100Gitlab-12.4.2持续集成服…

idm下载器 idm网络加速器 Internet Download Manager(IDM)免激活不弹窗版

idm下载器官方版英文名为Internet Download Manager。是一款界面简单、体积小巧下载速度飞快的下载工具&#xff0c;支持断点续传、多个任务同时下载&#xff0c;同时还支持限速下载&#xff0c;在自义文件类型里还可以自由设置下载的文件类型。 一、IDM软件安装 Internet Dow…

Linux安装Nginx及配置TCP负载均衡

目录 1、安装编译工具及库文件2、下载解压Nginx压缩包3、Ngnix配置Tcp负载均衡4、配置Ngnix的文件5、Nginx启动 1、安装编译工具及库文件 yum -y install make zlib zlib-devel gcc-c libtool openssl openssl-devel pcre-devel2、下载解压Nginx压缩包 wget https://nginx.o…

Docker 安装 Tomcat

目录 1. 总体步骤 2.安装tomcat 2.1 搜索 2.2 拉取 2.3 查看是否拉取到镜像 2.4 运行镜像 2.5 访问tomcat首页 1. 总体步骤 搜索镜像拉取镜像查看镜像启动镜像停止容器移除容器 2.安装tomcat 2.1 搜索 2.2 拉取 docker pull tomcat 2.3 查看是否拉取到镜像 docker …

连接医患的桥梁:深入了解互联网医院APP的开发与优化

当下&#xff0c;互联网技术的不断发展&#xff0c;越来越多的医院和医疗机构开始关注并投入到互联网医院APP的开发与优化中。接下来&#xff0c;小编将与大家共同探讨互联网医院APP的开发与优化。 一、互联网医院APP的开发原则 &#xff08;1&#xff09;用户体验至上 界面设…