【Linux】进程(7):地址空间

大家好,我是苏貝,本篇博客带大家了解Linux进程(7):地址空间,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
在这里插入图片描述


目录

  • (A) 直接看代码,看现象
  • (B)基本理解
  • (C)细节
    • 1. 如何理解地址空间
      • a.什么是划分区域
    • 2. 为什么要有地址空间
      • a.将无序变成有序,让进程以统一的视角看待物理内存以及自己运行的各个区域
      • b.进程管理模块和内存管理模块进行解耦
      • c.拦截非法请求
    • 3. 进一步理解页表
    • 4. 进一步理解写时拷贝

(A) 直接看代码,看现象

修改.c文件
在这里插入图片描述

运行进程
在这里插入图片描述

先看黄色框,这个我们能理解,因为之前说过父子进程的数据,如果任意一个都不对数据写入,那么数据就是共享的,所以它们指向同一块数据空间,所以地址相同

再看红色框,我们也能理解。因为进程具有独立性,所以子进程对数据的修改,父进程是看不到的,所以它们打印同一个全局变量,但值不同

再看蓝色框,这就不能理解了,同一个地址的值怎么可能既是100也是300?所以这个地址绝对不可能是物理地址,是虚拟地址。引出下一个概念:虚拟地址

(B)基本理解

当我们将程序加载进内存中时,OS在物理内存中一定要给这个程序开辟一块空间,来保存进程的代码和数据。OS要创建进程的task_struct。我们之前只说task_struct能指向内存中的代码和数据,事实远比我们想的复杂
在这里插入图片描述

在OS内部还要创建地址空间(每个进程都有独立的地址空间)。地址空间在32位机器和64位机器上的大小是不同的。我们以32位机器为例(下面讲的都是在32位机器下),地址空间从低到高一共有4GB的空间。我们之前用C语言打印的地址都是地址空间范围内所对应的地址,而非物理地址

进程的PCB会指向地址空间。

进程的代码和数据都在物理内存里面,进程想访问数据时,数据并不在地址空间上保存,地址空间会给我们提供线性的连续的地址(即虚拟地址),让我们未来提供虚拟地址找到物理地址

在这里插入图片描述

如何通过虚拟地址找到物理地址呢?
在计算机体系结构中还存在页表(每个进程都有自己独立的页表)。页表主要负责将地址空间的虚拟地址和对应的物理地址之间建立映射关系。只要建立好了映射关系,未来上层使用虚拟地址访问时,OS会自动拿着虚拟地址查页表转换成物理地址,最后访问到数据

在这里插入图片描述

现在有进程中有全局变量g_val,&g_val得到的0x601054是虚拟地址,假如g_val的物理地址是0x11223344,那么在页表中就会存储这些地址
在这里插入图片描述

现在进程创建了一个子进程,OS也会为子进程创建task_struct、地址空间和页表(每个进程都有自己独立的地址空间和页表)。
子进程没有代码和数据,它会继承父进程的代码和很多属性,相当于父进程pcb里的很多属性就可以用来初始化子进程。所以子进程的task_struct除了pid,ppid等,大部分属性都和父进程的一样。
子进程的地址空间和页表都是直接拷贝父进程的,所以子进程的地址空间里也有g_val的虚拟地址0x601054,子进程的页表里也有g_val的物理地址
在这里插入图片描述

现在让子进程对数据进行写入:将g_val的值从100改为300。
由于进程具有独立性,所以子进程对g_val的修改,不能影响父进程,所以肯定不能在0x11223344对应的空间修改。OS在写入时,发现g_val不仅被子进程在使用,还同时被父进程使用,所以写入暂停,OS在物理内存中重新开辟一块空间,假设物理地址为0x22334455,然后将g_val的值100拷贝到新空间中。再用新的物理地址覆盖页表中老的物理地址,重新构建映射。
上面的工作(叫写时拷贝)做完,OS再继续执行写入操作。将新的空间的值改为300

在这里插入图片描述

至此,子进程修改g_val的值,只是修改了物理内存和页表,可是上层用到的虚拟地址依旧是0x601054,虽然虚拟地址相同,但被映射到物理内存的不同的区域,所以出现了我们在(A)直接看代码,看现象里地址一样,但值不同的情况

(C)细节

为什么要写时拷贝?
我们上面说了是为了保证进程的独立性。那为什么不在创建子进程的时候,就把数据全部给子进程拷贝?因为如果有数据是父子进程都不需要修改的话,那将这些数据也给子进程拷贝一份,这不就是在浪费空间吗?所以,写时拷贝的本质就是按需申请

1. 如何理解地址空间

a.什么是划分区域

在小学的时候,大家都应该和同桌在桌子上划过“三八线”吧,现在假设你和同桌2个人共用一个100cm的桌子, 你们每个人50cm,那这如何用计算机语言来描述呢?
在这里插入图片描述

只需要构建2个结构体,第二个结构体表示一个课桌分为左右两部分,第一个结构体表示每部分的开始和结束位置,再构建第二个结构体的结构体变量,最后将左右两块空间的起始和终止位置都赋值即可

如果同桌太过分了,每次都侵占了属于你的10cm区域,再用计算机语言来描述

在这里插入图片描述

事实上,地址空间本质是内核的一个struct结构体(struct mm_struct),内核的很多属性都是表示start和end的范围。如何证明呢?

让我们来查看Linux的源代码,我们看到有许多表示开始和结束的变量

在这里插入图片描述

2. 为什么要有地址空间

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

如果没有地址空间,那么进程的task_struct就要能指向物理内存中对应的所有的数据和代码,这对进程来讲是比较困难的

在这里插入图片描述

现在有了地址空间和页表。实际的物理内存中,代码区、数据区、堆区……都是无序的,如果让进程的task_struct直接指向物理内存的对应的各种代码和数据区,那么可能从低地址往高地址,第一个是初始化数据区,第二个是堆区……就不像有了地址空间和页表,在进程的task_struct视角,从低地址往高地址一定是代码区、初始化数据区……
在这里插入图片描述

所以地址空间的第一个好处就是将无序变有序(对task_struct),让进程以统一的视角看待自己运行的各个区域

b.进程管理模块和内存管理模块进行解耦

比如现在进程要申请一段堆空间,那先在地址空间的堆区申请一段空间,但是进程不是立马就要用,所以暂时不在物理内存申请空间,也不在页表建立映射关系(只有虚拟地址,没有物理地址),等到进程需要用这段空间,再在物理内存申请空间并建立映射关系

换言之,如果要对进程做各种管理,那么内存管理都可以延迟处理,因此地址空间和页表的存在,能让进程管理模块和内存管理模块解耦

c.拦截非法请求

当我们写的代码在遍历时要访问地址空间的堆区(我们在上层使用的都是虚拟地址),但发生了越界,此时将这个越界的虚拟地址到页表中查,发现没有这个虚拟地址,证明没有对应的映射关系,所以OS就拦截了这次请求,不让它做任何操作,就不会有往物理内存中写入的操作,所以能拦截非法请求

3. 进一步理解页表

CPU内的寄存器(如CR3)能将当前页表的地址保存在CPU内
MMU(硬件):将虚拟地址结合页表转换成物理地址
在这里插入图片描述

页表中有许多标记位,比如用来确定当前物理地址指向的空间是否在内存中,是:标记位为1;否:标记位为0

什么情况下,当前物理地址指向的空间不在内存中呢?
进程挂起。如果操作系统内存特别吃紧,且进程处于阻塞态,那么操作系统会将内存中的代码和数据加载到磁盘的swap分区,那么此时物理地址指向的空间就不在内存中,该标记位就为0

页表中还有rwx权限标记位。我们以前见过下面的代码,你觉得这个代码能被VS运行通过吗?
在这里插入图片描述

显然不能,在语言层面上讲,因为”hello world”是常量字符串,位于字符常量区,所以不能被修改
在操作系统层面,就是字符常量区的虚拟地址在页表上的rwx权限标记位为r,没有w,所以在想将“web”写入时,系统检测到了错误,在转化成物理地址中将进程终止,所以根本没有写入物理内存

4. 进一步理解写时拷贝

在进程没有创建子进程时,全局变量g_val的虚拟地址被记录在页表中,对应的权限标记位为rw,可读可写

在这里插入图片描述

进程创建子进程后,全局变量g_val的虚拟地址被记录在页表中,对应的权限标记位被OS设为r。子进程会拷贝父进程的地址空间和页表,所以子进程的g_val在页表对应权限标记位也是r

在这里插入图片描述

当父子进程任意一个想对g_val进行写入时,将g_val的虚拟地址到页表中查,发现其权限标记位为r,OS识别到错误,开始判断

  1. 是不是数据不在物理内存(进程挂起了,页表中对应标记位为0):如果是,触发缺页中断(让OS重新在物理内存中开辟空间,重新建立映射,把标记位置为1,然后再继续访问)。这属于正常情况
  2. 是不是数据需要写时拷贝(OS如何知道需要写时拷贝,这个以后再讲),如果是,就发生写时拷贝
  3. 上面2种都不是,进行异常处理

好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

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

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

相关文章

法国人工智能初创公司 Mistral 正在推出新的人工智能模型定制选项服务和 SDK

Mistral AI是一家成立于2023年的法国人工智能初创公司,由Artur Mensch、Timothe Lacroix和Guillaume Lample三位前Meta和Google DeepMind的研究人员创立。该公司专注于生成式AI技术,特别是用于构建在线聊天机器人、搜索引擎等应用。 Mistral AI在成立之…

[数据集][图像分类]城市异常情况路边倒树火灾水灾交通事故分类数据集15223张8类别

数据集类型:图像分类用,不可用于目标检测无标注文件 数据集格式:仅仅包含jpg图片,每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数):15223 分类类别数:8 类别名称:[“badroad”,“fallentree”,“f…

CarSim车辆运动轨迹绘制

CarSim车辆运动轨迹绘制 CarSim中与车辆位置有关的信息分别为Xo和Yo 输出到Simulink中 导入到工作空间中保存,low_carsim_path.mat ,绘制结果曲线,low_carsim_path_comp.m data csvread(low_two_path.csv,1,0); low_two_path_x data(:,1)…

分享我的新版FMEA培训心得

近日,我有幸参加了深圳天行健企业管理咨询公司举办的新版FMEA培训,这次学习不仅让我对FMEA有了更深入的理解,更使我在实际工作中找到了提升产品质量的新路径。 新版FMEA相较于传统版本,更加注重风险识别与预防,强调在…

【递归、搜索与回溯】递归算法

一、经验总结 递归 VS 迭代(循环) 递归和迭代都解决的是重复的子问题,因此两者是可以相互转化的。利用栈结构可以将递归算法转化为迭代算法。 递归和迭代各有其优缺点,选择时需根据具体场景和需求来决定。 递归的优点包括&#…

苹果眼镜(Vision Pro)专业咨询服务模式优化方案

一、精准定位: 专注于为Apple Vision Pro应用开发者提供一站式、全方位的专业咨询服务,致力于成为开发者在空间计算时代中不可或缺的合作伙伴,共同打造“下一个大事件”。 二、核心业务优化: visionOS策略咨询: 深入…

【氵】Archlinux+KDE Plasma+Wayland 安装nvidia驱动 / 开启HDR

参考: NVIDIA - Arch Linux 中文维基 (其实就是把 wiki 简化了一下 注:本教程适用 GeForce 930 起、10 系至 20 系、 Quadro / Tesla / Tegra K-系列以及更新的显卡(NV110 以及更新的显卡家族),此处以 RTX3060 为例 …

LlamIndex二 RAG应用开发

在AutoGen)系列后,我又开始了LlamIndex 系列。欢迎查询LlamaIndex 一 简单文档查询 - 掘金 (juejin.cn)了解LlamIndex,今天我们来看看LlamIndex的拿手戏,RAG应用开发。 何为RAG? RAG全称"Retrieval-Augmented Generation&q…

vue处理json数据

背景:后端返回的数据不是我想要的,现在需要把 name 替换为title(小声蛐蛐:又让我处理数据) 后端返回数据格式 修改字段操作:(使用递归遍历的方式将title属性赋了name的值) renderT…

详细分析Mysql临时变量的基本知识(附Demo)

目录 前言1. 用户变量2. 会话变量 前言 临时变量主要分为用户变量和会话变量 1. 用户变量 用户变量是特定于会话的,在单个会话内可以在多个语句中共享 以 符号开头在 SQL 语句中使用 SET 语句或直接在查询中赋值 声明和赋值 SET var_name value; -- 或者 SE…

构建Vue3项目的几种方式,如何简化setup写法

1、说明 在vue2版本中,我们使用vue-cli脚手架进行构建,而切换到Vue3之后,依然可以使用vue-cli脚手架进行构建,但是官方推荐使用vite工具进行构建,下面将介绍几种方式构建vue3项目。 2、使用vue-cli脚手架构建Vue3项目…

【前端面试高频手写题】

# 面试高频手写题 建议优先掌握: instanceof - 考察对原型链的理解 new - 对创建对象实例过程的理解 call/apply/bind - 对this指向的理解 手写promise - 对异步的理解手写原生ajax - 对ajax原理和http请求方式的理解,重点是get和post请求的实现 # 1…

高考填报志愿,怎么分析自己适合什么专业?

高考结束后,很多考生不知道自己的分数段适合什么学校,缺乏目标感,有些专业名称很大,听起来光鲜亮丽,但是是否适合自己,学什么课程,将来就业去向,这些都是需要细致了解的。 专业选择…

matlab 异常值检测与处理——Z-score法

目录 一、算法原理1、算法概述2、主要函数3、参考文献二、代码实现三、结果展示四、相关链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 1、算法概述 使用Z分数法,可以找出距离平均值有多少个标准差值…

Python SQLAlchemy库详解

大家好,在Python生态系统中,SQLAlchemy库是一个强大的工具,为开发人员提供了便捷的方式来处理与数据库的交互。无论是开发一个小型的Web应用程序,还是构建一个大型的企业级系统,SQLAlchemy都能满足你的需求&#xff0c…

【操作与配置】MySQL安装及启动

【操作与配置】MySQL安装及启动 下载MySQL 进入官网,选择社区版下载 在windows安装 选择不登陆下载 安装MySQL 双击官方安装包 选择“Developer Default”(默认)即可 Execute,安装完成后next TCP/IP端口等,默认即可…

【TS】进阶

一、类型别名 类型别名用来给一个类型起个新名字。 type s string; let str: s "123";type NameResolver () > string;: // 定义了一个类型别名NameResolver,它是一个函数类型。这个函数没有参数,返回值类型为string。这意味着任何被…

路灯夜景视频素材去哪里找?傍晚黄昏夜景路灯视频素材网分享

在这个数字化的时代,视频创作者们总是在寻找各种优质素材来提升作品的质感。特别是充满浪漫氛围的路灯夜景,为短视频、电影、广告等增添了独特的视觉魅力。今天,我为大家整理了几个优秀的视频素材网站,帮助您轻松找到高质量的路灯…

flask 之JWT认证实现

目录 1、JWT 1.1、JWT概述 1.2、token的生成 1.3、token校验 1.4、flask项目中实现JWT认证 1、JWT 1.1、JWT概述 JWT(JSON Web Token)是一种用于身份验证和授权的开放标准。它由三部分组成,分别是头部、负载和签名。 头部&#xff0…

最新鲸发卡v11.61开心版 无后门发卡平台源码

安装说明 上传所有文件到服务器 或者宝塔 修改thinkphp伪静态,php版本为7.0 /install 安装 登录后台 /admin 定时任务计划设置 进入宝塔控制面板—–计划任务 填写计划任务 解冻任务 设置时间每小时第2分钟 执行 cd /www/wwwroot/website php think UnfreezeMoney 提…