当前位置: 首页 > news >正文

学习系统编程No.5【虚拟地址空间】

引言:

北京时间:2023/2/22,离补考期末考试还有5天,不慌,刚午觉睡醒,闹钟2点20,拖到2点50,是近以来,唯一一次有一种睡不醒的感觉,但是现在却没有精神,因为听了一首歌(当然洗脸更重要),天后孙燕姿的《直来直往》,三天170遍,上头,感兴趣的小伙伴可以去尝试一下哦!上篇博客我们学习了系统中环境变量等知识,现在我们接着系统环境变量的知识,来学习一下进程地址空间的相关知识

在这里插入图片描述

虚拟地址空间

什么是进程地址空间呢?让我们带着这个疑问,一步一步的来探索吧!首先我们在以前的知识中,学习过如果创建子进程(fork函数),并且明白进程其中的一个特性:独立性

所以明白这两点,看下图中的代码和运行结果,就可以很轻松的搞定
在这里插入图片描述
搞定了上述的代码和运行结构,此时我们就可以通过下述的代码和运行结果来引出进程地址空间的一个小知识点了,就是为什么父进程和子进程之间的地址是一样的呢?
在这里插入图片描述
看到上述代码,我们可以发现,利用进程的独立性,此时一个进程改变全局变量,并不会影响到另一个进程当中的全局变量,了解了这点,突然觉得进程真的是非常的神奇,看起来就是一个独立的个体一样,当然更神奇的是,这两个进程的地址是一样的,为了探索地址一样的问题,此时我们就找到了进程地址空间的切入点,从父子进程拥有相同的地址空间问题,引出地址空间的概念,接下来就让我们再次探索地址空间的知识吧!

复习有关内存的知识

当我们从上述例子之中得到了有关虚拟地址空间的概念之后,此时我们肯定是会有疑问的,比如:最大的疑问,为什么要有虚拟地址空间?电脑中不是存在内存(物理地址),为什么不使用内存(物理地址)呢?
此时在学习虚拟地址空间的概念之前,我们就先来复习一下以前学过的有关内存的相关知识,首先内存也叫存储器,是电脑中非常重要的硬件组成部分,因为有了存储器,才使电脑拥有的记忆功能,并且存储器可以分为内存和外存(磁盘),这里我们具体讲一讲什么是内存,内存也还可以进行细分,分为只读内存(ROM)和随机存取内存(RAM),注意:此时的ROM指的就是硬盘,也是属于内存中的一种哦!搞清了之间的关系,我们来看看存储器的组成,存储器主要是采用半导体器件和磁性材料构成,存储器的最小单元是存储元(由一个双稳态半导体电路或一个CMOS晶体管或磁性材料构成),然后由若干个存储元可以构成一个存储单元,最后存储器就是由许多的存储单元构成的,并且每一个存储单元可存放一个字节的空间,所以如果你的机器是一个32位的机器,此时就物理上就有32根地址线,有了32根地址线,当电脑进行通电的时候,就会产生32个正电/负电(1/0),此时就使我们的电脑有了32个由1/0构成的二进制序列,通过组合此时就有2^32 次方中可能,有了这么多的组合,此时就可以把这些组合和我们的存储元给结合在一起,通过各种二进制序列组合,给存储元编号,这种就使我们拥有的地址的概念,所以如果是一个32位的机器,此时他就有43亿左右(2的32次方)存储单元地址,此时每个存储单元存放一个字节,此时该存储器就拥有的4G左右的内存空间。(所以也就导致了,你如果想要使用内存,就必须把对应的信息给转换成二进制序列,这样才可以在内存中这么多的地址中寻找到对应的数据)如下图所示:

看到这幅图,我相信大家对内存的概念,应该会有更深层次的体会和认识吧!所以在我们电脑中的内存,也就是物理内存,本质上就是如上图的形式进行数据的存储。

为什么要有虚拟地址空间?

在了解为什么要有虚拟地址空间之前,我们先来谈谈操作系统的特性和基本功能,所有应用程序对硬件的操作都必须通过操作系统实现,并且为了防止硬件被失控的应用程序滥用向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备;操作系统此时需要通过抽象进程、虚拟内存和文件等概念来实现,如下图:
在这里插入图片描述
文件是对I/O设备的抽象表示,虚拟内存是对主存和磁盘I/O设备的抽象表示,进程则是对处理器、主存和I/O设备的抽象表示

明白了上述知识,引出关键概念:进程是对处理器、主存和I/O设备的抽象

所以此时就有了,当我们运行一个程序的时候,操作系统会提供一个假象,就好像系统上只有这个程序在运行。程序看上去是在独占地使用处理器、主存和I/O设备,处理器看上去就好像是在不间断地一条一条地执行该程序中的指令,即该程序的代码和数据是系统内存中唯一的对象;所以进程是操作系统对一个正在运行的程序的一种抽象,在一个系统上可以同时运行多个进程,而每个进程都好像在独占地使用硬件。

所以此时我们就明白了,一个进程在运行时,是独占所有的系统资源的

有了上述的知识,此时就可以引出我们想要学习的重点知识,为什么要有虚拟地址空间,理由如下:

  1. 在虚拟内存出现之前,程序寻址用的都是物理地址,因此程序能寻址的范围是有限的,具体寻址的范围是2^32也就是4G;
  2. 并且如果没有虚拟内存,那么每次运行进程就需要分配4G的物理内存给该进程使用,因为进程是对处理器、主存和I/O设备的抽象,是独占使用内存的,运行一个进程就需要把我们所有的内存供给其使用;
  3. 并且由于物理内存是有限的,当有多个进程要执行的时候,每个进程都需要分配4G内存,独占的使用所有的硬件,所以当内存被分配完之后,没有得到分配资源的进程就只能等待,当另一个进程执行完后,再将等待的进程装入内存,这种方式执行进程效率是非常低下的;
  4. 并且由于指令都是直接访问物理内存,那么进程就可以修改其他进程的数据,甚至会修改内核地址空间的数据,所以这种直接访问物理内存的方式是非常的可怕的,并且因为内存是随机分配的,所以程序运行的地址也是不正确的。

所以根据以上的种种原因,我们就需要引入一个叫虚拟地址空间的概念来尝试解决这些问题。

什么是虚拟地址空间

首先根据上述的知识,我们知道了为什么要有虚拟地址空间的概念,所以此时我们就正式来谈谈什么是虚拟地址空间,概念:每个进程创建加载的时候,会被分配一个大小为4G的连续的虚拟地址空间,虚拟的意思就是,其实这个地址空间时不存在的,仅仅是每个进程“认为”自己拥有4G的内存,而实际上,它用了多少空间,操作系统就在磁盘上划出多少空间给它。
通过概念,我们可以知道,虚拟地址空间的本质在我们的电脑中是不存在的(不像物理内存那样,拥有存储单元,每个单元一个字节),它是通过映射的形式将对应的数据存储在内存之中,具体说起来较为复杂,这里先不做了解。让我们看图来加深对虚拟地址空间的认识,如下图:

每个进程看到的虚拟地址空间由大量准确定义的区构成,如上图所示,每个区都有专门的功能

此时我们就来一一简单介绍一下这些区域的功能
  1. 程序代码和数据区(代码段):例如此时我们在执行一个C程序,对所有的进程来说,代码是从同一固定地址开始,紧接着的是和 C全局变量相对应的数据位置存放,代码和数据区是直接按照可执行目标文件的内容初始化的

  2. 堆:代码和数据区后紧随着的是运行时堆。代码和数据区在进程一开始运行时就被指定了大小,与此不同,当调用像 malloc 和free 这样的C标准库函数时,堆可以在运行时动态地扩展和收缩

  3. 共享库:大约在地址空间的中间部分是一块用来存放像C标准库和数学库这样的共享库的代码和数据的区域。共享库的概念非常强大,这里先简单介绍。

  4. 栈:位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数调用。和堆一样,用户栈在程序执行期间可以动态地扩展和收缩。特别地,每次我们调用一个函数时,栈就会增长;从一个函数返回时,栈就会收缩。

  5. 内核虚拟内存:地址空间顶部的区域是为内核保留的。不允许应用程序读写这个区域的内容或者直接调用内核代码定义的函数。相反,它们必须调用内核来执行这些操作。

总:虚拟内存的运作需要硬件和操作系统软件之间精密复杂的交互,包括对处理器生成的每个地址的硬件翻译。基本思想是把一个进程虚拟内存的内容存储在磁盘上,然后用主存作为磁盘的高速缓存

如何管理进程地址空间

通过上述的知识,此时我们明白了什么是虚拟地址空间,所以当我们想要执行一个程序的时候,该程序被加载到内存中,内存生成一个对应的PCB(task_struct)结构体,来管理该程序对应的代码和数据,此时的PCB中就存放这该进程的全部信息,此时就可以明白,我们的操作系统管理任何东西,都是通过先描述,再组织的方式,进行管理的(总而言之就是生成一个有合适成员变量的结构体),所以此时操作系统管理进程地址空间,也是通过先描述,再组织的形式,这样此时就又有了一个新的结构体( mm_struct ),专门给进程使用的结构体,也就是操作系统专门用来管理进程的结构体,所以,我们上述所说的进程可以独占的使用系统资源,本质上就是因为其被操作系统通过先描述,再组织的方式形成了一个结构体,就是一个内核数据结构而已

pcb和mm_struct和进程地址空间具体关系请看下图(搞清关系就行):
在这里插入图片描述

从上图可以看出,我们的task_struct结构体中是有一个结构体指针,指向着mm_struct进程结构体的

从物理内存理解虚拟内存

明白了上述的知识,此时我们知道,无论内存怎样虚拟化,最后肯定是都要放在物理内存之中,所以想要深入了解虚拟内存,此时就需要从物理内存的方面去理解,首先文章开始,我们已经复习过了物理内存的知识,这里就不多做介绍了,我们只要明白32位的机器,物理内存是通过2^32个字节的地址空间构成就行,并且如图,我们可以看出,物理内存是连续的,线性的,每个字节的空间是独立的(一个地址代表一个字节),所以当我们此时开辟了一个整形类型(int),此时就需要在线性内存中占4个连续的地址(因为一个地址只代表一个字节),所以本质上,开辟一个整形,向线性内存申请了4个不同的地址(地址连续),理解这个,我相信大家都有疑问,因为平时我们在调式,看变量地址的时候,并不可以看到4个地址,只能看到一个地址,所以此时就需要把这两个概念给结合起来理解,最终得出,本质上是4个地址,但是由于这些地址是连续的,方便查找的,所以,操作系统只是把4个地址中的最下面(编号最小)的那个地址(线性)给给我们,剩下的3个地址,是默认存在,只是你看不到而已;并且此时系统想要通过我们看到的那一个地址,找到剩下3个地址的话,就需要识别出该变量的类型(区别double、float、long),通过各个类型规定的字节大小,依次从内存中的地址向后读取,例:int,我们就再向内存读取三个字节,读取三个字节后就停止,double,就再向后读取7个字节,这样,我们就可以很好的把物理内存的地址给管理使用起来。

总:地址空间是线性结构

当我们了解到了,地址空间是线性的,那么可以知道我们的虚拟地址空间应该也是线性的,所以此时就如上述的虚拟地址空间图一样,我们可以把虚拟地址空间给划分成一个一个的区域,实现每个区域执行不同的功能,又因为,我们的操作系统,会将进程给抽象成一个结构体(mm_struct),如下图:

此时我们就知道,操作系统中的进程结构体就是通过一个一个的作用区域的开始(start)和结束(end)来控制进程虚拟地址空间,例如:当code_start = 100,code_end = 200,此时在该代码段中的100和200之间的区域表示的就是我们的虚拟地址,所以虚拟地址空间就是一个线性的结构,并且此时我们可以把这个结构通过结构体的方式定义成一个具有区域划分的新结构,并且可以通过改变某个区域的开始(start)和结束(end),来改变该区域的大小,例如:虚拟地址中的栈区和堆区的扩大缩小,就是通过这种形式来完成的。(注:只是简单理解,原理不会错,只是系统操作起来远复杂)

浅谈数据从虚拟地址空间拷贝到物理内存

这个问题是比较复杂的,感兴趣的同学请看这篇博客大佬博客

每个进程启动之后,操作系统都会自动生成一个该进程的页表用于存储的是虚拟地址和物理地址的映射,然后通过和CPU上的 MMU 进行交互,把虚拟地址翻译成物理地址,进而存储在物理内存之中(原理就是这样,但是实际复杂n倍)。

如下图所示:
在这里插入图片描述
通过上图,我们可以发现,为什么修改子进程的值,不会改变父进程的值,原因就是:当修改子进程中的值时,内存会自己重新开辟一块空间给你,然后把你的页表映射关系给改变,此时页表映射了位置就是新的空间,此时就可以实现子进程的值改变,并且因为页表是独立的,所以改变的只是物理内存和页表的映射关系,不会改变原虚拟地址中的值,所以此时就很好的证明了,子进程和父进程同一地址,但不同值的问题,并且因为此时在物理内存中开辟了两块空间,所以也解释了父子进程有两个返回值的问题。

使用虚拟地址空间的好处

1.防止地址随意访问,保护物理内存与其它进程
2.将进程管理和内存管理进行解耦合(本质上是为了提高操作系统效率和内存使用效率)
3.可以让进程以统一的视角,看待自己的代码和数据(进而忽略内存中的地址位置),提高运行效率

在这里插入图片描述

总结:系统中无论是什么东西,本质就是为了提高操作系统的效率,虚拟地址soso

相关文章:

学习系统编程No.5【虚拟地址空间】

引言: 北京时间:2023/2/22,离补考期末考试还有5天,不慌,刚午觉睡醒,闹钟2点20,拖到2点50,是近以来,唯一一次有一种睡不醒的感觉,但是现在却没有精神,因为听了…...

Linux常用指令(未完待续。。。)

* basename:只留下路径的“最后一部分” X、文件夹&目录操作 复制 :cp /xxx /xxx - a 该选项通常在拷贝目录时使用。它保留链接、文件属性,并递归地拷贝目录,其作用等于dpR选项的组合; - d 拷贝时保留链接&#…...

用D写裸机

原文 用D编写裸机RISC-V应用 这篇文章展示,如何用D编写,目标为RISC-VQEMU模拟器的程序裸机"你好".项目 为什么是D? 我最近一直在用C编写裸机代码,我有点对C缺乏特征感到沮丧.D引入了叫betterC的模式(基本上禁止了D运行时的所有语言功能).使得D裸机编程大致与C一…...

(二十五)、实现评论功能(5)【uniapp+uinicloud多用户社区博客实战项目(完整开发文档-从零到完整项目)】

1,实现二级回复的入库操作 1.1 两个子组件(comment-item和comment-frame)与父组件reply之间的属性传值 comment-item: props: {item: {type: Object,default () {return {}}}},comment-frame: props: {commentObj: {…...

【概念辨析】二维数组传参的几种可能性

一、二维数组传参竟然不是用二级指针进行接收? 今天进行再一次的二级指针学习时,发现了一条以前没怎么注意过的知识点:二维数组进行传参只能用二维数组(不能省略列)进行接收或者是数组指针。 问题复现代码如下&#xf…...

python和C++代码实现图片九宫格切图程序(附VS2015配置Opencv教程)

1、python代码实现图片分割成九宫格 需要包含的库,没有下载安装的,需要自己安装哦。 实现原理很简单,就是用PIL库不断画小区域,切下来存储成新的小图片。 假设每一个格子的宽和高分别是w、h,那么第row行&#xff08…...

【深度学习】优化器

1.什么是优化器 优化器是在深度学习的反向传播过程中,指引损失函数(目标函数)的各个参数往正确的方向更新合适的大小,使得更新后的各个参数让目标函数不断逼近全局最小点。 2.优化器 2-1 BGD 批量梯度下降法,是梯度下…...

SpringBoot使用validator进行参数校验

Validated、Valid和BindingResultBean Validation是Java定义的一套基于注解的数据校验规范,比如Null、NotNull、Pattern等,它们位于 javax.validation.constraints这个包下。hibernate validator是对这个规范的实现,并增加了一些其他校验注解…...

论文复现:风电、光伏与抽水蓄能电站互补调度运行(MATLAB-Yalmip全代码)

论文复现:风电、光伏与抽水蓄能电站互补调度运行(MATLAB-Yalmip全代码) 针对风电、光伏与抽水蓄能站互补运行的问题,已有大量通过启发式算法寻优的案例,但工程上更注重实用性和普适性。Yalmip工具箱则是一种基于MATLAB平台的优化软件工具箱,被广泛应用于工程界优化问题和…...

FastCGI sent in stderr: "PHP message: PHP Fatal error

服务器php7.2卸载安装7.4之后,打开网站一直无法访问,查看nginx错误日志发现一直报这个错误:2023/02/23 11:12:55 [error] 4735#0: *21 FastCGI sent in stderr: "PHP message: PHP Fatal error: Uncaught ReflectionException: Class translator does not exist in …...

【数字IC基础】跨时钟域(CDC,Clock Domain Crossing)

文章目录 一、什么是跨时钟域?二、跨时钟域传输的问题?2、1 亚稳态(单bit:两级D触发器(双DFF))2、2 数据收敛(多bit亚稳态)(格雷码编码、握手协议、异步FIFO、DMUX)2、3 多路扇出:(先同步后扇出)2、4 数据丢失(延长输入数据信号):类似脉冲展宽2、5 异步复位(…...

UNI-APP学习

uni-app的基本使用 uni-app介绍 官方网页 uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、H5、以及各种小程序(微信/支付宝/百度/头条/QQ/钉钉)等多个平台。 即使不跨端&#xf…...

编译原理【运行时环境】—什么是活动记录、 活动记录与汇编代码的关系

系列文章戳这里👇 什么是上下文无关文法、最左推导和最右推导如何判断二义文法及消除文法二义性何时需要消除左递归什么是句柄、什么是自上而下、自下而上分析什么是LL(1)、LR(0)、LR(1)文法、LR分析表LR(0)、SLR(1)、LR(1)、LALR(1)文法之间的关系编译原理第三章习…...

【Windows Server 2019】发布服务器 | 远程桌面服务的安装与配置 Ⅰ——理论,实验拓扑和安装基于RemoteAPP的RDS

目录1. 理论1.1 什么是远程桌面服务2. 实验拓扑2.1 拓扑说明3. 安装基于RemoteAPP的RDS1. 理论 1.1 什么是远程桌面服务 远程桌面服务 (RDS) 是一个卓越的平台,可以生成虚拟化解决方案来满足每个最终客户的需求,包括交付独立的虚拟化应用程序、提供安全…...

Bootstrap入门到精通(最全最详细)

文章目录前言一、Bootstrap是什么?二、Bootstrap安装方式一:将压缩包下载到本地引入使用方式二:使用Bootstrap官方cdn二.Bootstrap容器下面是屏幕宽度在不同大小时不同容器的显示状态三.Bootstrap栅格系统bootstrap网格系统有以下六个类网格系…...

C/C++每日一练(20230223)

目录 1. 数据合并 2. 回文链表 3. 完美矩形 1. 数据合并 题目描述 将两个从小到大排列的一维数组 (维长分别为 m,n , 其中 m,n≤100) 仍按从小到大的排列顺序合并到一个新的一维数组中,输出新的数组. 输入描述 第 1 行一个正整数 m , 表示第一个要合并的一维…...

c语言中const 是什么意思?(面试)

const关键字使用非常的灵活,在c中,const因位置不同有不同的作用,因情景不同有不同的角色,使用起来也是非常的灵活。 可以定义const常量,具有不可变性。 例如:const int Max100; Max会产生错误; 便于进行类…...

网络工程(三)ensp配置静态路由

配置静态路由 这里选择的路由器是AR2220 因为有三个GE接口 下面说拓扑图 一、定义AR路由ip地址和下一条 AR1system-viewsysname AR1interface g0/0/0ip address 10.0.0.254 8interface g0/0/1ip address 50.0.0.1 8下一条代码[AR1]ip route-static 0.0.0.0 0 50.0.0.2AR2 s…...

深入浅出C++ ——手撕红黑树

文章目录一、红黑树的概念二、红黑树的性质三、红黑树节点的定义四、红黑树的插入操作五、红黑树的验证五、红黑树的删除六、红黑树与AVL树的比较七、红黑树的应用八、红黑树模拟实现一、红黑树的概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存…...

Linux服务:Nginx服务重写功能

目录 一、重写功能 1、重写功能作用 2、rewrite指令 ①if指令 ②return指令 ③ set指令 ④break指令 3、rewrite标志 ①redirect标志 ②permanent标志 ③break标志 ④last标志 ⑤rewrite标志实验 一、重写功能 1、重写功能作用 重写功能(rewrite)用于实现URL的重…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...