【进程地址空间】地址空间理解存在原因 | 深入理解页表写时拷贝虚拟地址

目录

地址空间深入理解

划分区域

理解地址空间

地址空间存在的意义

意义1

意义2

意义3

理解页表和写时拷贝

页表

写时拷贝

OS识别错误 

理解虚拟地址

fork解释


上篇我们简单的学习了进程地址空间/页表/物理地址/虚拟地址/写时拷贝等概念。本篇深入理解下。

地址空间深入理解

划分区域

在我们初高中的时候,我们喜欢和我们同桌划分区域,是基于桌子进行区域的划分, 也可做出区域的调整。计算机语言是怎样表达的呢❓回答:结构体。

  • 地址空间本质是内核的一个struct结构体,内部很多的属性都是表示start,end的范围。
  • 地址空间浅显的理解:struct mm_struct (里面很多属性/字段/start&end)
  • 区域当中很多小的区域,每个区域都有自己的区域位置和范围,每个位置都可以被我们直接使用。不能简单的理解为限定了一段的区域范围。

 

 

理解地址空间

小故事tips:

  • 大富翁有很多个私生子(大富翁有10个亿)
  • 大富翁的私生子彼此不知道对方的存在,认为自己是独子(都认为自己可以继承这10个亿)
  • 每个私生子无论学习和工作都会向大富翁要小钱(每个人都认为相较于10个亿,自己要的钱是毛毛雨)
  • 所以,大富翁给每一个私生子画了一个大饼,承诺10个亿的遗产给他。
  • 大饼有10个亿,10个给每个私生子都是随便用。
  • 10个亿中的任何一块钱都可用。

  • 私生子:进程
  • 大富翁:操作系统OS
  • 物理内存:10个亿
  • 进程地址空间:大饼10个亿
  • 若私生子很多,大饼很多。都需要被管理起来。
  • 先描述再组织。
  • 同上,内存中任何一块空间都可以被OS使用(进程地址空间),取空间范围的下标,根据映射关系就可以找到物理内存空间了。

❗进程的地址空间的本质就是OS给进程画的大饼,告诉进程有这么多的空间范围可以使用。同时地址空间也需要被管理起来,先描述再组织。

❗每个进程都有自己的地址空间,地址空间是个结构体,结构体当中有各种代码区,数据区,各个区域(范围),各个区域的范围用来指定页表,(多个连续的地址,通过页表的映射到物理内存)

地址空间存在的意义

  • 将无序变成有序,让进程以统一的视角看待物理内存以及自己运行的各个区域。
  • 进程管理模块和内存管理模块进行解耦
  • 拦截非法请求

意义1

每个程序都有自己的代码和数据加载到物理内存(程序从磁盘加载到内存中,代码和数据不是线性存放的)。同时OS创建程序的进程控制块PCB。要求每个进程的PCB必须要记录程序的代码和数据再物理内存的位置。

  • ❗进程task_struct中记录程序的数据和代码在物理内存的位置比较有负担的
  • ❗越界访问,修改到其他进程的数据/代码情况都是存在的
  • ❗PCB记录位置是相对的,比较混乱的,OS对程序的数据/代码内存管理,调整非常不方便。
  • 不同的数据在物理内存的不同区域中。
  • 实际中的物理内存中,代码区,数据区,堆区,栈区,共享区,命令行参数和环境变量都是存在于不同的位置的。

对比增加地址空间/页表:

  • 将无序变成有序,让进程以统一的视角看待物理内存以及自己运行的各个区域。
  • 使用进程地址空间,统一,可以线性连续的访问各个区域的地址。
  • 进程地址空间的区域范围只有大小的区别。
  • 页表:虚拟地址到物理地址的映射就可以将无序变为有序。    

 

意义2

场景:

  • 假设程序的代码时2MB,现在已经执行了1MB了,还有1MB等待执行。
  • 此刻OS发现物理内存空间不够,把已经完成的1MB空间释放掉,
  • 把页表中关于部分的映射关系去掉,
  • 把已经执行的1MB的数据唤出到外设当中,使其处于挂起状态。

❗如果没有进程地址空间,那么进程当中就只有1MB的数据在物理内存中的地址信息。如果要再次使用也就没有了。

❗存在地址空间,进程地址空间仍然存在2MB的数据在物理内存中的地址信息。


  • OS在创建进程地址空间时,把数据和代码在物理内存中地址信息(虚拟地址)放到进程地址空间。
  • 申请一段堆/栈等空间(用start/end指针调整申请大小范围)
  • OS不着急申请物理内存,只有当真正的需要访问的时候才来申请物理内存,形成页表,映射关系。
  • 也就是说OS创建进程时也会开辟进程的数据/代码的虚拟地址空间,不会立刻开辟物理内存,只有当要使用物理内存的时候才会开辟。(❗提高内存的使用率)
  • 对进程进行的任何调度/管理各方面都可以稍后延迟管理/调度。
  • 如果在申请进程的地址空间的同时也申请物理内存,但没有使用。物理内存在OS层面上就相当于在没有使用的时间段被浪费了。

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

通俗来讲,以进程的角度来申请内存只要认为地址空间的能申请即可,物理内存可等待......

意义3

  • 若进程可以直接访问物理内存的某个位置,不存在进程地址空间/页表映射这一步。若进程访问越界了,直接可能导致修改了物理内存中别的进程的数据。造成无法挽回的错误❌
  • 若存在进程物理空间/页表,访问越界,根据虚拟地址空间到页表中找不到对应的映射关系,页表和地址空间(这个查询过程)都是OS操作的。则会被OS拦截,根本不会到达物理内存。避免了无法挽回的错误✔(硬件)
  • OS会错误访问的请求直接拦截,不会涉及物理内存。防止进程向物理内存中写入错误数据,而是影响其他内存块。(拦截非法请求)

进程的地址空间不会100%的使用,只会使用地址空间一部分。空间在应用层确实存在,进程可能出现越界访问的情况(非法访问),若存在进程地址空间的存在,OS会直接拦截非法访问❌。所以的非法请求都不能通过地址空间到物理内存(保护物理内存)。

理解页表和写时拷贝

页表

  • CPU中的存在寄存器CR3:保存当前进程页表的虚拟地址。
  • CPU中的工作单位MMU(硬件)(Memory Management Unit 存储器管理单位)。
  • MMU:快速把CPU寄存器中的虚拟地址结合当前的进程的页表转化成物理地址。
  • MMU可以直接找到进程的页表。
  • 页表是非常复杂,后面我们也会慢慢讲解理解❗

  • 页表除了映射关系,还存在一些选项/字段/标记位。
  • 数据存在于物理内存当中,标记位为1;不在,为0。
  • 代码只能读,是r权限。
  • 数据只能读,是r权限;可读可写,是rw权限。

  • 物理内存严重不足,进程的代码和数据会被唤出内存,到磁盘交换分区Swap分区。进程处于挂起状态。
  • 此刻,进程的页表的标识位为0,表示不在物理内存中。
  • 权限为rw,可以读写。权限r,可以读。
  • 页表的虚拟地址保存,物理地址释放,物理内存空间也释放。虚拟地址空间仍然存在,进程仍然存在。
  • 系统/语法,同时这也是我们在Linux和windows写了一个崩溃的程序,并不影响其他进程的OS。因为这个程序的进程崩溃动作有任何向物理内存写入和影响,仅仅在地址空间和页表就被返回了(权限不允许)。如果可以写入,证明这个写入动作是合法的。

char *str = "hello world";

*str = 'H';

  • 为什么字符常量区不能被修改❓为什么只读❓
  • OS层面上保证的,字符常量在虚拟地址中通过页表映射到物理内存中,每个区域都是通过页表映射,字符常量在页表的映射关系标志位权限时只读。

写时拷贝

写时拷贝:是浅拷贝解决浅拷贝析构冲突的一种解决方案,写时拷贝也叫延时拷贝,几个对象共用一块空间,当执行读操作时不会有影响,当你需要进行写操作改变一个对象的内容时,空间的值不能被修改,会互相影响,那么就需要单独开辟一块空间将对象拷贝过去然后改,不改变就不需要开辟。

写时浅拷贝与深拷贝比较的优点:占用空间少(相同内容不开辟新空间),复制效率高。


malloc()等内存分配函数,在分配时只是建立了进程虚拟地址空间,并没有分配虚拟内存对应的物理内存。(虚拟地址是合法的)

当进程访问这些没有建立映射关系的虚拟内存时,处理器自动触发一个缺页异常

缺页中断:在请求分页系统中,可以通过查询页表中的状态位来确定所要访问的页面是否存在于内存中。每当所要访问的页面不在内存时,会产生一次缺页中断,此时操作系统会根据页表中的外存地址在外存中找到所缺的一页,将其调入内存。 

OS识别错误 

调度进程的时候,OS在地址空间/页表就识别到进程的错误有三种情况:

  • 是不是数据不在物理内存(挂起状态)(怎样判断:缺页中断)
  • 是不是数据需要写时拷贝(发生写时拷贝)(怎样判断后面讲:技术技术)
  • 如果都不是,才进行异常处理

怎么判断进程的是写时拷贝/还是非法访问❓ ☞后面讲

理解虚拟地址

  • 虚拟地址空间就是OS内核中的一个结构体,
  • 结构体当中包含了各种各样的区域/划分,
  • OS在构建加载进程时,也会进程对应的进程地址空间和页表。
  • 通过页表对非法请求进行拦截,同时也便于我们内存,
  • 我们就可以根据虚拟地址找到物理地址,好处以统一的视角看待内存,
  • 同时也会便于我们管理,提高内存的利用率。

❓在最开始的时候,地址空间/页表中的数据从哪里来(虚拟地址)

❓每个进程的代码区和数据区等的大小不一样,说明随着程序的不同,每个程序的模块区域都不一样大,都是要初始化虚拟地址从哪里来。

❓程序的编译成功形成的可执行程序.exe之后,函数名和变量名还存在吗。

不存在。全是地址。

  • 程序没有加载到内存当中的时候,全是二进制的时候,本身存在地址。
  • 对程序进行编制,这个地址就是虚拟地址(逻辑地址)
  • 在代码编译的时候,代码已经被编址过了,编址好了区域段,地址空间的内容都已经编址好了。0-4GB,天然的,线性的,平坦模式。(平坦模式编译)
  • 通俗来说,OS创建进程的地址空间时,在编译器编译程序阶段,就已经把地址空间的内容都准备好了,加载到内存中,直接使用即可。
  • 地址空间和页表的数据直接从程序读取来。
  • CPU根据物理地址找到虚拟地址,创建进程的地址空间和页表,从而让进程找到物理地址。
//命令行查看反汇编
objdump -S myprocess
objdump -S myprocess >test.c

fork解释

❓对于fork的返回值为什么返回两次

❓一个变量怎么可能既是 == 0 ,又是 > 0

  • 无论是子/父都要return,所以会return两次。
  • id原是父进程的变量
  • id本来是r权限(只能读)
  • 再fork创建子进程之后
  • id写入时,id为rw权限,发生写时拷贝
  • 则id存在两个值
  • return XXX return 的本质就是对id进行写入,发生写时拷贝❗
  • 代码用的同一个变量id,同一个变量在被编译器编译的时候,得到是同一个虚拟地址,fork创建子进程/页表/地址空间,子父指向同一个变量,当其中任何一方要return时,写入,发生写时拷贝,所以虚拟地址相同,物理内容不一样。id出现两个值的情况。
  1 #include<stdio.h>2 #include <sys/types.h>3 #include <unistd.h>4 5 int main()6 {7     pid_t id=getpid();8     pid_t parentid=getppid();9     printf("process is running,id=%d,parentid=%d\n",id,parentid);//只有父进程10     sleep(3);11     pid_t ret= fork();//创建子进程12     if(ret == -1)13     {14         return 1;15     }16     else if(ret == 0)17     {18         printf("I am child process!,pid=%d,ppid:%d\n",id,parentid);19         sleep(2);20     }                                                                          21     else//ret>022     {23         printf("I am parent process!,pid=%d,ppid:%d\n",id,parentid);24         sleep(2);25     }return 0;}

🙂感谢大家的阅读,若有错误和不足,欢迎指正。下篇Linux2.6内核进程调度队列,来学个具体的例子。

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

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

相关文章

Ubuntu系统下 Nvidia驱动 + cuda驱动 + CuDNN安装与卸载

Ubuntu系统下 Nvidia驱动 cuda驱动 CuDNN安装与卸载 一、NVIDIA驱动与CUDA驱动的区别二、NVIDIA驱动安装与卸载1. 查看系统内核版本2. 查看显卡型号3. 查看是否有显卡驱动4. 禁用nouveau并重启5. 卸载旧版本6. 安装&#xff11;&#xff1a;使用标准Ubuntu仓库进行自动化安装…

学习笔记Day21:转录组差异分析

转录组差异分析 差异分析难点在于将数据处理成需要的格式 表达矩阵 数值型矩阵-count 行名是symbol 低表达量的基因需要过滤 分组信息 因子&#xff0c;对照组在level第一位 与表达矩阵的列一一对应 项目名称 字符串&#xff08;不要有特殊字符&#xff09; TCGA-XX…

路由策略实验

一.实验拓扑图&#xff1a; 二.实验要求&#xff1a; 1.按照图示配置IP地址&#xff0c;R1,R3,R4上使用loopback口模拟业务网段 2.R1和R2运行RIPv2&#xff0c;R2&#xff0c;R3和R4运行OSPF&#xff0c;各自协议内部互通 3.在RIP和OSPF间配置双向路由引入&#xff0c;要求除R4…

PHP 函数的命名空间是否会影响执行顺序?

在 php 中&#xff0c;函数命名空间一般不会影响执行顺序。执行顺序通常由文件顺序或函数调用顺序决定。即使函数位于不同的命名空间中&#xff0c;只要它们在同一文件中&#xff0c;它们就会按照定义顺序执行。 PHP 函数命名空间是否会影响执行顺序&#xff1f; 简介 在 PHP…

pygame 烟花效果

# 初始化 pygame.init() screen_width 800 screen_height 600 screen pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption(烟花效果) # 焰火发射 particles [] # 焰火粒子 def firework(x, y): num_particles 100 # 每次发射的…

关于ResNet的假说

ResNet 最核心的思想就是 恒等映射吧 那么现在来提出几个问题&#xff1a; 为什么deeper 以后train L 会增加&#xff1f;恒等映射会解决什么问题&#xff1f;能否解决梯度非常陡峭的问题&#xff1f;你想到了什么模型有类似的问题&#xff0c;如何进行改进的&#xff1f; as…

本地环境通过ssh通道连接服务器数据库,实现本地客户端和代码可以访问数据库

使用方法&#xff1a; ssh -p 搭建隧道的端口 -fNL 本地端口:远程ip:远程端口号 搭建隧道的账号搭建隧道的ip 可以增加参数-v,输出更多的信息 ssh -p 搭建隧道的端口 -fNL 本地端口:远程ip:远程端口号 -v 搭建隧道的账号搭建隧道的ip 有时候&#xff0c;测试环境的数据库不允许…

ClickHouse 数据类型、表引擎与TTL

文章目录 数据类型表引擎1.TinyLog 引擎2.MergeTree 引擎3.ReplacingMergeTree 引擎4.AggregatingMergeTree 引擎5.SummingMergeTree 引擎6.CollapsingMergeTree 引擎7.Distributed 引擎 TTL列级 TTL表级TTL 数据类型 ClickHouse 数据类型Java 数据类型数据范围UInt8Short0 到…

获取肖博数学全套视频+讲义

肖博数学是一个专业团队&#xff0c;教学方法非常颠覆&#xff0c;具有很多技巧&特殊的解题方法内容&#xff0c;能使得学生在高考时冲刺高分 hello&#xff0c;今天分享一下高中数学资料&#xff0c;肖博数学&#xff0c; 他们的教学方法与传统的教学方式有所不同&#…

vue实现周日历 日历按周切换 vue日程管理

实现的功能 1、点击今天&#xff1a;回到今日日期并选中今日日期&#xff0c;查当天数据 2、点击左箭头&#xff1a;切换上一周 3、点击右箭头&#xff1a;切换下一周 4、黄圆圈代表有日程提醒&#xff0c;点击选中&#xff0c;下方对应显示当前日程提醒的内容&#xff0c;没有…

C++设计模式|创建型 4.建造者模式

1.什么是建造者模式? 建造者模式&#xff08;也被成为生成器模式&#xff09;&#xff0c;是一种创建型设计模式&#xff0c;软件开发过程中有的时候需要创建很复杂的对象&#xff0c;而建造者模式的主要思想是将对象的构建过程分为多个步骤&#xff0c;并为每个步骤定义一个…

nlp 自然语言处理的dataset数据库积累

下面的这个和 entity recognition有关的。 Weights & Biases

3i平台体验性能加持,13600KF+B760M+撼与科技A770 TITAN装机体验

在2022年&#xff0c;intel重启显卡线&#xff0c;带来了多款性价比十分不错的显卡。而近段时间&#xff0c;又有传言说intel第二代产品e即将面世&#xff0c;甚至已经有数款Battlemage GPU曝光&#xff0c;让不少intel忠实粉丝直呼期待&#xff0c;或许在今年年底&#xff0c;…

mysql面试题八(SQL语句)

目录 1.SQL 基本组成部分 常用操作示例 创建表 插入数据 查询数据 更新数据 删除数据 创建索引 授予用户权限 2.常见的聚合查询 1. 计数&#xff08;COUNT&#xff09; 2. 求和&#xff08;SUM&#xff09; 3. 平均值&#xff08;AVG&#xff09; 4. 最大值&…

Opencv | 图像卷积与形态学变换操作

这里写目录标题 一. 滤波 / 卷积操作1. 平滑均值滤波/卷积2. 平滑中值滤波/卷积3. 平滑高斯滤波/卷积3.1 关注区域3.2 分解特性 二. 形态学变换1. 常用核2. cv.erode ( ) 腐蚀操作3. cv.dilate ( ) 膨胀操作4. Open 操作5. Close 操作6. Morphological Gradient 形态梯度操作7.…

设计模式之创建型模式---工厂模式

文章目录 工厂模式概述简单工厂简单工厂的代码实现简单工厂的使用简单工厂应用场景 工厂方法工厂方法模式的代码实现工厂方法的使用工厂方法应用场景 抽象工厂抽象工厂模式代码实现抽象工厂的使用方法抽象工厂模式的应用场景 总结 工厂模式概述 工厂模式从名字就能看出&#x…

Threejs绘制传送带

接下来会做一个MES场景下的数字孪生&#xff0c;所以开始做车间相关的模型&#xff0c;不过还是尽量少用建模&#xff0c;纯代码实现&#xff0c;因为一方面可以动态使用&#xff0c;可以调节长度和宽度等&#xff0c; 下面这节就做一个简单的传送带&#xff0c;这是所有车间都…

基础SQL DML-插入语句

插入语句前&#xff0c;我们先创建一个表。表的创建在DDL语句里面涉及&#xff0c;可以参考&#xff1a;小赖同学吖-CSDN博客 我们创建一个员工表进行数据的插入操作 插入&#xff08;添加&#xff09;语句的语法 给员工表添加一条记录 给员工表添加多条记录 也可以通过下面的方…

年薪5.8万美元|临床医生赴美国康奈尔大学从事博士后研究

作为临床医学8年制的博士毕业生&#xff0c;A医生希望能到国外从事一段时间的博士后&#xff0c;以强化基础科研训练&#xff0c;弥补职业发展的短板。最终我们为其申请到康奈尔大学Weill Cornell医学院的博士后职位&#xff0c;年薪为5.8万美元。 A医生背景&#xff1a; 申请…

C语言项目实践——贪吃蛇

引言&#xff1a;本篇博客中&#xff0c;我将会使用结构体&#xff0c;链表&#xff0c;WIN32 API等一系列知识完成C语言项目——贪吃蛇的实现。在观看此篇博客之前&#xff0c;请将这些知识所熟悉&#xff0c;不然可能会造成理解困难。 更多有关C语言的知识详解可前往个人主页…