Linux初识地址空间

前言

上一期我们对进程优先级、命令行参数以及环境和变量做了介绍!以前我们就提到过一个问题有了运行队列为什么还要有优先级?本期将带你揭晓!

本期内容介绍

虚拟地址空间的引入

虚拟地址空间的介绍

如何理解地址空间

为什么要有地址空间

如何进一步理解页表和写时拷贝

解决历史遗留问题

虚拟地址空间

1.1虚拟地址空间的引入

OK,我们先来看看这样的一段代码:

这段代码是创建了父子进程,分别打印其pid、ppid以及一个全局变量的值和地址, 5秒后子进程把g_val给修改成了300;OK,我们来看看结果:

这里的结果是,前5秒父子进程都是打印的100,5秒后子进程把g_val修改了变成了300, 所以以后子进程的g_val就是300,而父进程的不变!这一点也可以理解,我们知道进程=task_struct(PCB)+其代码和数据;fork之后产生了子进程,而子进程的本质是在操作系统中多了一个进程即多了一套task_struct(PCB)+代码和数据,而以前介绍过子进程的代码是可以继承父进程的,如果子进程不对数据修改,子进程和父进程共享数据(注意:这里可没说子进程继承父进程的数据!!);这里子进程虽然修改了数据但父子进程具有独立性,所以父子进程数据也得想办法独立,可以理解的!但是让我们震惊的根本就不是这个,而是父子进程的g_val的地址是一样的!按照以往的理解就是一个变量既等于100又等于300,这怎么可能??所以我们可以得出一个结论:上面g_val的地址绝对是物理地址!!!,不是物理地址(物理内存的地址)那是啥呢?其实这是虚拟地址!!

1.2虚拟地址空间的介绍

虚拟地址空间我们是学习过的,在C语言、以及C++的时候都是介绍过的;就是下面这个:

不过当时在C语言和C++没有介绍是因为,这个东西本身就不是语言的问题,而是操作系统层面的知识!例如上面的例子,如果没有学系统,看到上面的代码后三观直接震碎!OK,言归正传,继续上回到虚拟地址空间上,以前我们介绍过:当一个进程在被调度时,会先把他的代码和数据加载到内存,然后操作系统会为其创建一个PCB(task_struct)来描述该进程的属性,并把PCB以某种数据结构组织起来,方便管理,即"先描述,在组织"!其实,当一个进程加载到内存时系统并不会只创建一个PCB,还会创建地址空间和页表来一起管理该进程!

我们以前所有程序的地址都是虚拟地址,并非物理地址!这里的虚拟地址就是你虚拟地址空间的地址,每个进程再被加载前都会为其分配一个虚拟地址空间!

页表是进行虚拟地址和物理地址转换的!

页表和虚拟地址空间本质也是和PCB一样的进程内核数据结构,所以系统也会对其进行管理的,如何管理?先描述,在组织!

如下图:

OK,和以前的一样不在多说~!所以,有了虚拟地址空间和页表的介绍,我们就可以理解上述的g_val父子进程的地址为什么是一样的了!

fork之后有了子进程,即有了子进程的代码和数据、PCB、虚拟地址空间、以及页表!其中代码、PCB(pid、ppid等除外)、虚拟地址空间、页表都是继承自父进程的;此时,父进程和子进程的地址空间的内容是一模一样的,所以他们指向的数据也是一样的,即此时数据形成浅拷贝!也就是我们前面所说的父子进程共享数据,而后面子进程对数据修改了,此时操作系统检测到了之后会对子进程的数据进行写实拷贝(OS自主完成的,用户感受不到),然后让子进程修改,所以子进程修改的是父进程数据的拷贝,所以子进程修改后父进程的g_val不变!这也符合我们介绍的,进程具有独立性!

如下图:

OK,理解了这里就可回答下面的问题了!

1、如果父子进程不对数据进行修改,是不是父子进程共享的呢?

是的,刚刚上面介绍了,父子进程如果不对数据进行修改,他们是都是共享一份数据的!

2、为什么要实行写实拷贝?可不可以在创建子进程时,把父进程的数据全部给子进程拷贝一份?

写实拷贝的本质是一种按需申请,通过拷贝的时间顺序达到有效节省空间的目的!

例如,进程的数据有环境变量、命令行参数等这些子进程几乎是不会修改的,如果你直接在创建子进程的时候拷贝一份话,会造成不必要的空间浪费!因为这些东西很少修改,父子进程共享即可,如果等到子进程真正的需要修改的时候给他开空间,写入即可!另一方面,即使子进程真的有内存需要,例如他在5秒后要一段malloc或new的空间,如果是一开始给子进程拷贝一份的话,前5秒他不用,这样一来是不是在5秒的时间内浪费了这一块空间?系统说不一定在这5秒内可以拿着这些空间做更多的事情,如果是写实拷贝的话,一开始只给页表一个虚拟地址,其对应的物理地址可以不给,等到真正用的时候再去申请即可!这样就提升了内存实时的使用效率!

1.3如何理解地址空间?

地址空间的本质就是内核的一个struct结构体!内部有很多的start和end,表示某个区域的范围!

我们举个例子就可以理解了:

假设你是一个上小学的文静的小男生或小女生,你的同桌是一个非常邋遢的同学,是不是把这放桌上,把那放桌上,你有一次受不了了,就在桌子上画了一条38线, 假设桌子长100cm,38线是在50cm处;左边属于你,右边的属于他!此时你对你们的桌子进行了区域划分,同理,你有一块内存空间,要分为很多的区,是不是也可以向上面的38线一样分区!

假设你同桌今天又把鞋子放到你桌边上了,你一起之下,把38线向右移动了20厘米直接73开:

所以这样就把区域划分变成了对每个对象的start和end的修改!其实内核中也是类似这样的,OK,来看看内核中的地址空间的区域划分:

1.4为什么要有地址空间?

要理解这个问题就先得理解好地址空间!OK,还是来一个例子:

在遥远的漂亮国有一个土豪,他有n个私生子,这些私生子相互不知道对方的存在!现在土豪先找到大儿子,说Tom最近老爹听说你在微软上班了?大儿子说嗯,土豪说可以不愧是我儿子,好好干老爹我现在身价100亿美金,等以后都是你的!大儿子一听好呀好呀~!然后土豪又找到二儿子,他二儿子在考博士,土豪说儿子听说你在考律师的博士?二儿子说是的老爹,土豪同样又说,好好学等你以后成功了,老爹的这100亿都是你的,二儿子也是很高兴的同意了~!过了几天这个土豪又找到他的私生女,说小爱呀听说你在做珠宝生意?小爱说是的呢,然后同样的套路给小爱说老爹现在又100亿你好好干以后都是你的~!小爱也点了头,然后又找到了它的小儿子说儿子听说你在准备申请上大学??小儿子点了点头,土豪又说,你只要能够申请到中国的清华大学老爹的这100亿都是你的.....

这里的土豪就是操作系统,这里的每个私生子就是每个进程,土豪给每个私生子(进程)画的大饼就是虚拟地址空间!

理解了这些现在再来谈一下为什么要有地址空间!主要有以下3个原因:

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

2、进程管理和内存管理进行解耦

3、拦截非法的请求(对物理内存的保护)

4、使每个进程保持独立性

什么意思呢?就是通过虚拟地址空间可以让每一个进程都以为自己的数据永远在某个地址处(虚拟地址)无需关心物理内存在哪里,其实它的真实的数据可能在物理内存的另一地址处!这样进程就变得更加好管理进程和内存了,这其实也是一种封装和C++STL迭代器类似,看似都一样,其实底层天差地别!这样每个进程都觉得每一个进程都是操作系统的唯一,而其实并不是~!关于拦截非法的请求,也是举个例子:比如说数组越界,其实是虚拟地址空间映射到页表时页表就已经检查出来了,这样就防止了对物理内存的随便乱访问,即保护了物理内存!

1.5如何进一步的理解页表和写实拷贝?

关于页表,我们这里只是非常简单的介绍了一下,什么多级页表都没提,这里只是先简单的见一下,后面动静态库以及多线程会在次介绍的!!这想说的意思是不要把页表像的过于简单了!OK,页表不光是对虚拟与物理地址的映射,还可以对非法的请求进行拦截即权限标志位的检查、是否在内存等!OK,再举个栗子:

char* str = "hello";
*str = 'H';

这段代码一执行就挂了,原因是给静态区的常量字符串赋值了!OK,语言层面是这样讲的,但是现在的问题是为什么不能够对静态区的常量赋值呢?其实是在赋值的时候再页表的时候被页表给拦截了!因为页表内部有一个标记位标记的是该地址处的数据是否有相应的权限,常量区的数据那必然只有写权限,你一写入页表就拦截了反馈给OS,操作系统就把你的进程给搞挂了~!

也就是,如果你的进程在进京某种操作时,都会经过页表的检查,如果合法让你操作物理内存,否则反馈给OS,OS会交给判断处理!例如,你的代码比如说由于内存压力大给把一部分挂起到磁盘了,当你进程在访问时页表一查虚拟地址存在但是物理地址不存在,此时发生错误,交给OS,OS检查完后发现是发生了缺页中断;再比如说在写入时发现要该数据被多个进程同时引用,此时反馈给OS,发现需要写实拷贝!如果上述都不是就需异常处理!

1.6历史遗留问题

我们在以前刚刚接触子进程的时候,这段代码:

当时看到一个变量的值即是大于0又是等于0,感觉三观直接崩塌了,其实现在介绍了虚拟地址空间后,现在再来看是很好理解的,fork后要return xxx;本质是对同一个变量id的写入,不管是谁先返回即写入就会发生写时拷贝,然后父子进程有了自己独立的物理内存的id而正在虚拟地址层面上他们的地址还是一样的!

OK,本期内容就介绍到这里,好兄弟,我们下期再见~!

结束语:我们不应该被眼前的一些所谓的华丽所迷惑,更应坚守初心,一步步的朝目标前进!

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

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

相关文章

Elasticsearch:智能 RAG,获取周围分块(一)

作者:来自 Elastic Sunile Manjee 在检索增强生成 (RAG) 领域,一个持续存在的挑战是找到输入大型语言模型 (LLM) 的最佳数据量。数据太少会导致响应不足或不准确,而数据太多会导致答案模糊。这种微妙的平衡启发我开发了一个专注于智能分块和利…

花钱就能过?PMP到底有没有用

在项目管理领域,PMP(Project Management Professional)认证常被看作是专业能力的金牌标准。 然而,伴随着这一认证的普及,也出现了一些质疑声,比如“PMP认证是否只是金钱和时间的投入就能获得的证书&#xf…

Mybatis工作流程和插件开发

在了解插件开发之前,我们先总体的来梳理一下Mybatis的大致执行流程: 1.new SqlSessionFactoryBuilder().build(inputStream):先根据配置文件(包含了全局配置文件和映射配置文件)初始化一个对象Configuration(这里对象里…

Java | Leetcode Java题解之第155题最小栈

题目&#xff1a; 题解&#xff1a; class MinStack {Deque<Integer> xStack;Deque<Integer> minStack;public MinStack() {xStack new LinkedList<Integer>();minStack new LinkedList<Integer>();minStack.push(Integer.MAX_VALUE);}public void …

哈喽GPT-4o——对GPT-4o 文本创作的思考与看法

目录 用法1&#xff1a;创作小说用法2&#xff1a;创作散文用法3&#xff1a;创作诗歌1、古诗2、现代诗 用法4&#xff1a;创作儿童故事用法5&#xff1a;创作剧本 大家好&#xff0c;我是哪吒。 都说ChatGPT4o是目前文本创作的最强大模型&#xff0c;它都可以用于哪些方面的文…

虚拟化 之四 详解 jailhouse 使能和创建 Cell 的工作流程

完整的 Jailhouse 组件主要由内核模块(jailhouse.ko)、虚拟机管理程序固件(jailhouse*.bin)、管理工具(jailhouse 命令行程序及一些 Python 脚本)以及配置文件(.cell)这四部分组成。用户使用它们来启用虚拟机管理程序、创建 Cell、加载 inmate 二进制文件以及运行和停止…

CCPD数据集

官网&#xff1a;https://github.com/detectRecog/CCPD 其它介绍&#xff1a;https://blog.csdn.net/qianbin3200896/article/details/103009221 CCPD (Chinese City Parking Dataset, ECCV) provinces ["皖", "沪", "津", "渝", &…

跟着刘二大人学pytorch(第---13---节课之RNN高级篇)

文章目录 0 前言0.1 课程视频链接&#xff1a;0.2 课件下载地址&#xff1a; 1 本节课任务描述模型的处理过程训练循环初始化分类器是否使用GPU构造损失函数和优化器每个epoch所要花费的时间遍历每个epoch时进行训练和测试记录每次测试的准确率加入到列表中 具体实现&#xff0…

0基础可以直接学python自动化测试吗?

可以直接学习Python自动化测试&#xff0c;即使没有编程基础。Python是一种易于学习和上手的编程语言&#xff0c;也是自动化测试领域中最受欢迎的语言之一。下面是一篇超详细和规范的文章&#xff0c;将从零开始介绍Python自动化测试的基础知识。 1. 安装Python和开发环境 首…

项目进度和成本管理

1.如何正确标识出软件项目活动&#xff1f; 正确标识软件项目活动是项目管理中的一个重要步骤&#xff0c;它有助于确保项目的顺利进行和成功完成。以下是一些标识软件项目活动的步骤和建议&#xff1a; 项目范围定义&#xff1a;首先明确项目的目标和范围&#xff0c;这将帮助…

初识前端开发

目的 &#xff1a;开发一个网站 -前端开发&#xff1a;html 、css、javaScript -web框架&#xff1a;接收请求处理 -mysql数据库&#xff1a;存储数据的地方 快速上手&#xff1a; 基于Flask web框架让你快速搭建一个网站出来 学习&#xff1a; 基于Django框架 初识HTML …

刷代码随想录有感(106):动态规划——分割等和子集(01背包问题)

题干&#xff1a; 代码&#xff1a; class Solution { public:bool canPartition(vector<int>& nums) {int sum 0;for(int i : nums){sum i;}if(sum % 2 ! 0)return false;int target sum / 2;vector<int>dp(10001, 0);for(int i 0; i < nums.size(); …

Windows11和Ubuntu22双系统安装指南

一、需求描述 台式机电脑&#xff0c;已有Windows11操作系统&#xff0c;想要安装Ubuntu22系统&#xff08;版本任意&#xff09;。其中Windows安装在Nvme固态上&#xff0c;Ubuntu安装在Sata固态上&#xff0c;双盘双系统。开机时使用Grub控制进入哪个系统&#xff0c;效果图…

Python进阶:从函数到文件的编程艺术!!!

第二章&#xff1a;Python进阶 模块概述 函数是一段可重复使用的代码块&#xff0c;它接受输入参数并返回一个结果。函数可以用于执行特定的任务、计算结果、修改数据等&#xff0c;使得代码更具模块化和可重用性。 模块是一组相关函数、类和变量的集合&#xff0c;它们被封…

第 2 章:Spring Framework 中的 IoC 容器

控制反转&#xff08;Inversion of Control&#xff0c;IoC&#xff09;与 面向切面编程&#xff08;Aspect Oriented Programming&#xff0c;AOP&#xff09;是 Spring Framework 中最重要的两个概念&#xff0c;本章会着重介绍前者&#xff0c;内容包括 IoC 容器以及容器中 …

Yum安装LAMP

查看当前80端口是否被占用 ss -tulanp | grep 80查询httpd是否在yum源中 yum info httpd安装httpd yum -y install httpd启动httpd服务&#xff0c;设置开机自启 systemctl enable httpd --now systemctl start httpd查看当前进程 ps aux | grep httpd查看当前IP&#xff…

自动化技术如何影响企业数据分析的发展

当今时代&#xff0c;企业普遍面临着转型的压力&#xff0c;这些挑战主要源于在科技和市场的双重压力下如何实现增长。当前&#xff0c;企业发展的趋势是紧追自动化的浪潮&#xff0c;并通过优化预算管理流程&#xff0c;推进系统和数据分析的现代化。在这一过程中&#xff0c;…

LoRA用于高效微调的基本原理

Using LoRA for efficient fine-tuning: Fundamental principles — ROCm Blogs (amd.com) 大型语言模型的低秩适配&#xff08;LoRA&#xff09;用于解决微调大型语言模型&#xff08;LLMs&#xff09;的挑战。GPT和Llama等拥有数十亿参数的模型&#xff0c;特定任务或领域的微…

怎样搭建serveru ftp个人服务器

首先说说什么是ftp&#xff1f; FTP协议是专门针对在两个系统之间传输大的文件这种应用开发出来的&#xff0c;它是TCP/IP协议的一部分。FTP的意思就是文件传输协议&#xff0c;用来管理TCP/IP网络上大型文件的快速传输。FTP早也是在Unix上开发出来的&#xff0c;并且很长一段…

Vue54-浏览器的本地存储webStorage

一、本地存储localStorage的作用 二、本地存储的代码实现 2-1、存储数据 注意&#xff1a; localStorage是window上的函数&#xff0c;所以&#xff0c;可以把window.localStorage直接写成localStorage&#xff08;直接调用&#xff01;&#xff09; 默认调了p.toString()方…