【Linux进阶之路】进程(中)—— 进程地址空间

文章目录

  • 一、 进程地址空间
    • 1.概念引入
    • 2.基本概念
    • 3.深入概念
      • 3.1 初识信息交互
      • 3.2 区域划分
      • 3.3 进程地址空间
      • 3.4 再识页表
        • 缺页中断
        • 进程挂起
  • 总结

一、 进程地址空间

1.概念引入

  • 指针指向的地址是内存中的地址吗?下面我们用一个实验来证明一下。
  1. 先来写程序看一下程序的地址分布。

在这里插入图片描述

  1. 查看并分析运行结果:

在这里插入图片描述

  • 可见是符合预期的结果的。

说明:在Windows下的内存分布可能不一样,实际情况要看具体的操作系统,如果细究,在各个区域定义一个变量,打印其地址进行验证。

  1. 创建子进程修改一个指定变量,然后查看其地址。
  • 实验代码
    在这里插入图片描述
    再回顾一下之前的知识:
  1. fork创建子进程,对父进程返回子进程的pid,对子进程返回0。
  2. 父子进程对只读的代码共享(写时拷贝)。

说明:这里我们是对id变量的修改。

  • 运行结果与分析
    在这里插入图片描述

说明:

  1. 物理地址是内存某一位置的实际地址,且物理地址是唯一的(因为就一块内存)。
  2. 此处假设是物理地址,那么其中的值必然是相同的,但是这里不同,显然不是物理地址。
  • 结论与引入:既然不是物理地址,那存放的是什么地址呢?我们一般称之为虚拟地址/线性地址
  • 那如何解释上述地址相同的现象呢?

2.基本概念

在这里插入图片描述

  • 虚拟地址存放的空间,我们一般叫做进程地址空间,如上图。

说明:
程序中变量存的是虚拟地址,不是物理地址,那我们之前学的就是错的吗?
解释:

  1. 很显然不是,是因为所占的角度不一样。
  2. 首先写代码时我们是站在应用层的角度进行考虑的;
  3. 其次我们目前学操作系统,是从偏硬件的角度进行理解的;
  4. 而且学了进程地址空间,只会让我们理解的更深,更加偏向底层。
  5. 因此我们之前学的不是错的,只是理解尚浅。

 而且虚拟地址一定能够转换为物理地址,如何转换呢?—— 页表

  • 原理:类似哈希表的结构,其虚拟地址->物理地址。

现在我们尝试画图解决一下之前的问题:

  1. 对上述程序的指定行进行解读:

在这里插入图片描述

  • fork创建完子进程未返回。
  1. 通过对父进程进行拷贝(浅拷贝),对代码和数据进行拷贝,生成跟父进程几乎一样(数据与代码的虚拟地址完全相同)的进程地址空间(独有的pid不一样)。
  2. 对页表进行拷贝,生成一模一样的页表。
  3. 此时的父进程与子进程的id变量指向同一块物理地址。

图解:
在这里插入图片描述

  • fork返回,对子进程返回0,对父进程返回子进程的pid。
  1. 写入过程中由于父子进程指向同一块物理空间,因此操作系统给子进程再申请一块物理空间,并将子进程页表的物理地址进行修改,虚拟地址不变。
  2. 对子进程id变量的物理空间写入0。
  3. 对父进程id变量的物理空间写入子进程的pid。

图解:
在这里插入图片描述

  • 那如何解释上述地址相同的现象呢?

3.深入概念

3.1 初识信息交互

问题1:CPU 、内存、输入输出设备如何进行交互?
解释:

  1. 通过"线"进行交互。
  2. 线细分为三种,地址总线,数据总线,控制总线。
  3. 线简单分为两种,CPU与内存的线称为系统总线,内存与输入输出设备的线称为IO总线。

问题2:线是什么?为什么要用线?
解释:

  1. 线简单理解就是用于进行数据传输的通道。
  2. 线的主要作用是确保计算机组件之间能够进行协调通信与合作。
  3. 用线的另一个原因在于生产各个部件的厂商不同,但各个部件又需要结合才能使用,因此只需用线将不同的部件结合,在整机效率不变的基础上提升了生产效率。

问题3: 从硬件的角度解释,计算机是如何产生01序列的?
解释:

  1. 低电频产生低位0,高电频产生高位1。
  2. 每根线可产生0/1,两种电频,在32位(32根线)的机器下,能产生232种电频信号,因此32位机器最多存放232 byte的数据也就是4GB。

3.2 区域划分

 前面我们只是初始概念,下面我们通过问题来对概念进一步的理解。

  1. 区域划分是什么?请结合进程地址空间进行思考。

下面博主讲个故事引入理解:

 回想起美好而又纯洁的青春,一定发生过类似这样的故事。

小帅:hello!大家好,我是小帅。

在这里插入图片描述
小美:hi ! 大家好,我是小美。
在这里插入图片描述

  • 那些同桌之间发生的事:

 小帅与小美是同桌,两个人用的是双人桌,小帅有点喜欢小美,想着吸引小美的注意,于是就趁着小美不注意,就用胳膊戳小美,惹的小美不知该如何是好,于是抱着忍一时风平浪静的心态就没搭理小帅,小帅看着无动于衷的小美,心想按照剧本应该理一下我猜对啊,难道得玩把大的?年轻的我们总是想着吸引喜欢人的注意,而不知道出发的方式,于是小帅又趁着小美不注意,正想要顺走小美最喜欢的笔,此时被小美发现了,小美这下子忍不住了,想着老娘不发威,你当老娘是病猫,于是揪着小帅的耳朵,给小帅了一顿"奖励" , 小帅暗想终于理我了,于是跪地求饶,说着姑奶奶绕了我吧,你要我干什么我都答应你,于是小美想着,这臭小子不知到哪回就越界了,于是就说这样吧,我画一条线,你敢越过这条线,就等着挨打吧!小帅嘴上说着,我一定不会再越了,可心里怎么想的,没人知道……

在这里插入图片描述

 故事的重点在于——划线的操作。

  • 划线的本质就是区域划分。
  • 这样做的好处就是防止越界,使空间分配合理化。
  • 当访问的范围不在自己的区域时,直接进行报错,在自己的区域时,就正常运行,这正是小美与小帅的故事背后的逻辑。
  • 进程地址空间的代码区,常量区,数据区,这三个区域的划线操作是在编译期间就确定的。,也就意味着编译时就进行划线。
  • 堆区,栈区,其边界是动态变化的,随着运行时变量的开辟与销毁而变化。意味着边运行边划线。

那在操作系统中是如何划线的呢?

struct mm_struct 
{//....unsigned long total_vm, locked_vm, shared_vm, exec_vm;unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;unsigned long start_code, end_code, start_data, end_data;     /*维护代码区和数据区的字段*/unsigned long start_brk, brk, start_stack;       /*维护堆区和栈区的字段*/unsigned long arg_start, arg_end, env_start, env_end;  /*命令行参数的起始地址和尾地址,环境变量的起始地址和尾地址*///....
};

说明:

  1. 进程地址空间本质上就是一个数据结构对象。
  2. 那操作系统如何对对象进行管理呢?当然是先描述,再组织,最后形成与PCB类似的mm_struct对进程地址空间进行管理。
  1. 虚拟地址的分布是规律的,那物理地址呢?
  • 首先虚拟地址与物理地址通过页表的映射进行联系起来。
  • 其次从进程的角度来看,虚拟地址已经是很便于进行管理。
  • 而且只需管理虚拟地址,物理地址也被间接的被有规律的管理了起来。
  • 因此物理地址没必要再是有序的。
  • 总的来看可以认为物理地址是乱序的存储,有序的被间接管理
  1. 从操作系统的角度看,程序最终如何管理变量,是变量名吗?
  • 首先程序代码由编译器与链接器处理之后,只剩下了二进制指令,不存在变量名。
  • 其次从内存的角度看,获取到了地址,即获取到了数据,因此在底层是通过不断更改地址来获取数据的。

3.3 进程地址空间

  1. 进程相互之间是如何做到独立的?

我们再来讲一个故事:

  • 从前有一个大富翁,身价十个亿,而且到处沾花惹草,但是却让3个女人,心甘情愿地为他生了三个儿子,可见"超"能力是多么的有魅力。

  • 由于这位大富翁是一位时间管理大师,对三个儿子照顾的很好,竟然让这三个儿子都不知道彼此之间的存在。

  • 随着大富翁一天一天的老去,也开始思考如何分配遗产,由于对三个儿子都很疼爱,于是做个一个这样的决定:分别对三个儿子说:儿子," 爹老了,等爹去世了,这十亿资产就是你的了。"

  • 因为都认为父亲只有我这一个儿子,因此三个儿子都对此深信不疑。

  • 于是有一天儿子甲经济困难,来找大富翁要20万美金,大富翁二话没说,直接往儿子甲卡里打了30万美金,儿子甲屁颠屁颠的走了;

  • 儿子乙因为快要上大学了,于是问大富翁要了10万美金,大富翁也二话没说,直接往儿子乙身上打了20万。

  • 儿子丙因为一事无成,于是整天想着继承大富翁的十亿家产,于是选择一天,鼓足勇气的给大富豪说,“爹,我现在就想继承十亿家产”,大富翁很是生气,于是就怼过去,“你爹还没死呢!就想着继承家产了。” 就直接让儿子丙滚了,儿子丙也觉得没有什么不对,就走了。
    ……

  • 故事到这里就讲完了,回归到操作系统,这里的大富翁的十亿资产对应的是一整块物理内存,大富翁对应的是操作系统,而这儿子对应是进程

  • 进程在申请内存时,本质上是操作系统申请的,由操作系统决定是否分配给进程空间,而进程与进程在申请内存之间没有联系。

  • 其次每个进程有属于自己的进程地址空间,也就意味着有着各自的虚拟地址。

  • 而物理地址实际上是由操作系统进行分配与管理的,两者之间没有联系。

  • 但是由于页表的存在,建立了映射关系,可以将虚拟地址与物理地址联系起来。

  • 但进程与操作系统还是各管各的,只不过通过页表的修改而将虚拟地址与物理地址统一起来。

问题:进程为什么不直接在内存上使用物理地址,而非得通过虚拟地址进而使用物理地址?
解释:

  1. 虚拟地址也是地址,在没有通过页表映射的物理地址之前,操作系统可以进行一层检查,从而过滤掉非法的申请信息,就比如在32位的机器下,申请4GB的内存。
  2. 内存只有一块,也就意味着物理地址是唯一的,如果直接使用物理内存,也就意味着将内存地址暴露给了用户,一旦用野指针修改其中的未知区域,报错可能会导致整个系统的瘫痪!
  3. 结构相同的进程地址空间,即虚拟地址存放的位置,意味着可泛化,统一的管理,从而便于进程对进程地址空间的管理。
  4. 一般我们将进程的操作称作进程管理模块,而操作系统的管理内存的模块称作内存模块,两者通过页表和进程地址空间,即物理地址与虚拟地址进行解耦合,更加的独立。

3.4 再识页表

问题1:页表如何判断虚拟地址非法?
解释:

  1. 页表记录的信息不只有虚拟地址与物理地址的映射,还记录着虚拟地址的权限。
  2. 比如当修改常量区的代码时,这时页表通过其权限判断只有可读权限,由此直接报错,不进行修改。

问题2: 页表的地址是虚拟地址还是物理地址?页表的地址存在哪?
解释:

  1. 不可能是虚拟地址,因为页表存的是虚拟地址与物理地址的映射,如果其还为物理地址,相当与自己存自己的虚拟地址与物理地址的映射,就套娃了,其次也没必要进行存储。
  2. 进程加载到CPU上,页表在进行加载地址时,会将其地址放在cr3寄存器中进行加载,放的肯定是物理地址,在进程运行完毕时,会将其地址放在进程的上下文进行带走,以便于下一次的恢复。
缺页中断

在这里插入图片描述

 这就要再从父进程拷贝子进程具体过程再来理解了。

  1. 子进程在拷贝父进程的时,会共享数据和代码。
  2. 子进程在拷贝父进程页表时,栈区的地址在拷贝过程中其权限会发生转变,由写权限变为读权限。
  3. 在对子进程栈区的数据进行修改时,由于是读权限且在栈区,这时操作系统会再帮子进程申请一块空间,并将其物理地址修改成申请的物理地址再将子进程页表相应的权限改为写权限。


总的来看,在发生页表的当前权限与实际权限发生冲突时,会触发缺页中断。

进程挂起
  • 在Linux中我们只看见过R,S,D,T状态,那挂起状态我们并没见过,那有没有呢?
  • 从定义的角度来看,所谓进程挂起,也就是进程的代码和数据,不在内存而在磁盘当中。
  • 那如何判断数据是否在内存呢?
  • 其实很简单,在页表上打一个标记,比如1表示在,0表示不在。

举个例子:当你启动一个大型游戏,比如说原神。

  1. 在原神的启动时,先生成其进程PCB,进程地址空间,页表。
  2. 在加载代码和数据的过程中,我们的内存并不可能加载所有的数据,这样内存会爆的。
  3. 因此内存采用一种惰性加载的方式,即用什么加载什么。
  4. 因此在用的时候,查看页表其虚拟地址对应的物理地址是否在内存中,如果不在,操作系统就会把相应的数据和代码加载到内存中,然后再进行执行。

总的来看:这里的页表的本该存在实际不存在发生冲突,从而触发了缺页中断。

总结

问题1:我们再来看一看进程是由什么组成的?
解释:在原先的PCB数据结构对象 + 代码和数据的基础上,再加上了进程的上下文,进程地址空间(mm_struct),页表。

  • 初步认识了进程地址空间与页表,并对程序的底层有了更深的了解。

 今天的分享就到这里了,如果感到有所帮助,不妨点个赞鼓励一下吧!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# Onnx Yolov8 Detect 戴安全帽检测

效果 项目 代码 using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms;namespace Onnx…

pd19虚拟机软件 Parallels Desktop 19 mac中文停用功能

Parallels Desktop 19 mac是一款功能强大的虚拟机软件,它允许用户在Mac电脑上同时运行Windows、Linux和其他操作系统。Parallels Desktop提供了直观易用的界面,使用户可以轻松创建、配置和管理虚拟机。 Parallels Desktop 19 for Mac停用功能 从Paralle…

python+unittest+requests+HTMLRunner编写接口自动化测试集

问题描述: 搭建接口测试框架,执行用例请求多个不同请求方式的接口 实现步骤: ① 创建配置文件config.ini,写入部分公用参数,如接口的基本url、测试报告文件路径、测试数据文件路径等配置项 1 [DATABASE] 2 data_addre…

xcode15一直显示正在连接iOS17真机问题解决

前言 更新xcode15之后,出现了各种报错问题,可谓是一路打怪啊,解决一个报错问题又来一个。没想到到了最后还能出现一个一直显示正在连接iOS17真机的问题 一直显示正在连接iOS17真机的问题 问题截图如下: 解决方法 1. 打开De…

使用canvas做了一个最简单的网页版画板,5分钟学会

画板实现的效果:可以切换画笔的粗细,颜色,还可以使用橡皮擦,还可以清除画布,然后将画的内容保存下载成一张图片: 具体用到的canvas功能有:画笔的粗细调整lineWidth,开始一个新的画笔…

紫光同创FPGA实现HSSTLP高速接口通信,8b/10b编解码数据回环,提供PDS工程源码和技术支持

目录 1、前言免责声明 2、我这里已有的 GT 高速接口解决方案3、设计思路框架HSSTLP详解HSSTLP基本了解HSSTLP之时钟HSSTLP之PCSHSSTLP之PMAHSSTLP之接口说明 硬件设计HSSTLP IP调用和配置 4、PDS工程详解5、上板调试验证并演示6、福利:工程代码的获取 紫光同创FPGA实…

js实现在报表参数界面获取body中控件的值

要在报表参数界面获取body中控件的值,你可以使用JavaScript来实现。下面是一个详细的介绍: 1. DOM(文档对象模型): - DOM是用于操作HTML文档的API,它允许你通过JavaScript访问和操作文档中的元素。 - 在报…

网络通信和tcp协议

一、计算机网络架构模型 1、OSI七层模型 2、TCP/IP模型 3、TCP/IP协议族 无论是什么网络模型,都是为上一层提供服务,抽象层建立在低一层提供的服务上,每层都对应不同的协议 4、地址和端口号 1)MAC地址 MAC 地址共 48 位&#…

ARM映像文件组成

引言 ARM编译器将各种源文件(汇编文件、C语言程序文件、C语言程序文件)编译生成ELF格式的目标文件(后缀为.o文件,以下将目标文件简称为.o文件),.o文件经过连接器,和C/C运行时库一起编译生成ELF格…

visual studio Qt 开发环境中手动添加 Q_OBJECT 导致编译时出错的问题

问题简述 创建项目的时候,已经添加了类文件,前期认为不需要信号槽,就没有添加宏Q_OBJECT,后面项目需要,又加入了宏Q_OBJECT,但是发现只是添加了一个宏Q_OBJECT,除此之外没有改动其它的代码,原本…

十四天学会C++之第八天:文件操作

1. 文件的打开和关闭 文件操作的基本概念。打开文件:使用fstream库打开文件以供读写。关闭文件:确保文件在使用完毕后正确关闭。 文件的打开和关闭:C 文件操作入门 在C编程中,文件操作是一项重要的任务,可以读取和写…

51单片机KeyWard

eg1: 单片机键盘的分类 键盘分为编码键盘和非编码键盘,键盘上闭合键的识别由专用的硬件编码器实现,并产生键编码号或键值得称为编码键盘,如计算机键盘,而靠软件来识别的称为非编码键盘,在单片机组成的各种…

网络协议--UDP:用户数据报协议

11.1 引言 UDP是一个简单的面向数据报的运输层协议:进程的每个输出操作都正好产生一个UDP数据报,并组装成一份待发送的IP数据报。这与面向流字符的协议不同,如TCP,应用程序产生的全体数据与真正发送的单个IP数据报可能没有什么联…

党建展馆vr仿真解说员具有高质量的表现力和互动性

随着虚拟数字人应用渐成趋势,以虚拟数字人为核心的营销远比其他更能加速品牌年轻化进程和认识,助力企业在激烈的市场竞争中脱颖而出,那么企业虚拟IP代言人解决了哪些痛点? 解决品牌与代言人之间的风险问题 传统代言人在代言品牌时&#xff0…

寻找一罐app里的隐藏海

一、前言 (一)一罐app简介 一罐app 是一款小众交友软件,可以匿名or真身发布动态 (二)开发目的 因为某些原因,某些板块被隐藏起来了。(一罐称板块为xxx海) (三&#…

产品研发团队协作神器!10款提效工具大盘点!

在如今科技驱动的时代,产品研发团队面临着前所未有的竞争压力和不断变化的市场需求。为了在这个激烈的环境中脱颖而出,团队需要高效协作并充分利用先进的工具来提高生产力和创新能力。 本文将为你盘点产品研发团队协作必备的10个提效工具,这…

1-07 React配置postcss-px-to-viewport

React配置postcss-px-to-viewport 移动端适配 安装依赖:在项目根目录下运行以下命令安装所需的依赖包: npm install postcss-px-to-viewport --save-dev配置代码 const path require(path);module.exports {webpack: {alias: {: path.resolve(__di…

hive窗口函数记录

记录工作中和学习中的窗口函数,方便以后使用,本记持续更新和完善,版本:231019 文章目录 1.什么是窗口函数2.窗口函数的表达式3.窗口函数的类型1) 排名函数2) 聚合函数3) 跨行取值函数 4.[frame…

TX Text Control.NET For WPF 32.0 Crack

TX Text Control 支持VISUAL STUDIO 2022、.NET 5 和 .NET 6 支持 .NET WPF 应用程序的文档处理 将文档编辑、创建和 PDF 生成添加到您的 WPF 应用程序中。 视窗用户界面 功能齐全的文档编辑器 TX Text Control 是一款完全可编程的丰富编辑控件,它在专为 Visual Stu…

mariadbmysql更改数据库默认存储路径

1.登录数据库查询默认存储位置 默认存储在/var/lib/mysql show variables like "%datadir%"; 2.先停止服务 systemctl stop mariadb 3.移动数据文件 mv /var/lib/mysql/ /home/ 4.修改服务配置 vim /etc/my.cnf.d/server.cnf5.在 [mysqld] 下面增加 datadir/ho…