【Linux 学习计划】-- 进程地址空间

article/2025/6/17 23:50:50

目录

进程地址的引入

进程地址空间基础原理

区域划分的本质

如何理解进程地址空间

越界访问的本质

进一步理解写时拷贝

重谈 fork 返回值

结语


进程地址的引入

我们先来看一段代码:

首先我们可以看到,父进程和子进程是可以同时可以看到一个变量的,这也很正常,因为子进程的数据最开始就是从父进程那里来的

但是我们现在再来看一个代码:

唯一的改动在这里,接下来我们来看一下结果:

这对吗?注意看,这上面两个变量的地址是一样的,但是两个变量的值却是不一样的,这不对啊!!

不知道各位有没有想起我们在学习进程的时候,最开始学到的一个函数,叫做fork,这个函数的返回值也是可以同时返回给同一个参数,但是当时我们就说,这是由于有两个不同的进程,但是我们没有就着那个变量来谈

但是就用最基础的知识来讲,我们就有理由怀疑,这两个变量并不是同一个变量,并且这两个地址也不是同一个地址

事实也确实如此,这就是我们接下来要讲解的——进程地址空间

进程地址空间基础原理

我们先来看这样一张图

实际在我们的系统中,进程和内存之间,在逻辑上并不是紧紧相连的

我们进程中的数据,都是要先被放进一个叫做地址空间的地方上,而我们上面G_VAL的地址,其实就是这里的地址空间的地址

接着还有一个页表,页表负责映射地址空间的地址与物理内存的地址(比如左边是虚拟地址,我们在页表中就可以根据这个虚拟地址查询到某个变量在物理内存中具体被存放在哪里)

我们现在将上面这张图拆开来进行讲解:

今天我们有一个父进程,然后这个父进程有自己的进程地址空间,也有页表

现在父进程里面有一个变量,叫做G_VAL,值是100

注意,比如这个时候我们的代码实际是保存在物理内存中的

现在我们对这个父进程执行fork操作,那么就有了所谓子进程:

子进程也是一个进程,他也需要自己的进程地址空间和页表

子进程一开始什么都没有,但是他会直接将父进程的数据全部拷贝一遍(不包括代码,像代码这些只需要在物理内存保存一份,所有人都能看到就行了),包括变量G_VAL的值,在页表中与物理内存的映射,原原本本的全部拷贝一份(但是代码是没有拷贝的,因为这个是只读的,直接看父进程的就好了)

这个时候,我们的子进程就做到了,能和父进程“看到”一样的数据

G_VAL会在进程地址空间中有一个虚拟地址,经过页表映射,在物理内存上就能找到真实存放的位置

但是如果我们现在对G_VAL进行修改,那么写时拷贝就发生了,由于前面虽然是两个不同的进程,但是在物理内存上看到的本质上是同一个

这时候我们子进程想要修改这个变量,那么内存就只能再开辟一段空间,来存放一个新的变量,虽然这个变量也叫做G_VAL

但是,我们的虚拟地址并不会改变,因为没有改变的必要,页表倒是需要变一变,只不过虚拟地址那一部分不变,变的只是映射到物理内存的那个地址

所以这也就是为什么,我们在代码中看到的同一个地址,同一个变量,不同的值

本质上,那些都是虚拟地址,但是在内存中,这是两个完全不一样的值(如果没有修改值,没有发生写实拷贝的话那就是同一个值)

接下来我们可能会有两个疑问:

1. 子进程到了修改的时候才发生写实拷贝,效率怎么听起来会慢一点啊?

其实是不会的,因为如果这个变量没有改变的话,那我们就连拷贝都不需要,就算是发生了修改,那如果一开始就开辟空间,和要改了才开辟,其实就只是今天写作业和明天写作业的区别,到头来都是要写的

但是如果学校老师不检查的话,那甚至这个作业都可以不写(只是举例,思想上不倡导哈)

2. 为什么不在最开始的时候,将所有的数据都拷贝给子进程,不是说进程是相互独立的吗?

这个其实也没得说,像代码,环境变量等等,这些东西,大家看到的都是同一个,何必要全部拷贝呢?能省空间就省空间嘛,内存的空间也不是这么浪费的

区域划分的本质

如下图(其实还是上面的图的一部分):

我们会看到,进程地址空间是被划分成了一个个小位置的,比如栈区、堆区、静态区这些

先来说说为什么要这么分,他的意义是什么

试想一下,如果我们没有进程地址空间的话,那么我们的变量将会直接在内存上开辟,先不谈安全问题(比如越界访问),如果直接在内存上开辟,我们的变量在内存上的地址是否就要被记录下来,这样我们下一次才能找到这个变量并且进行使用

但是如果今天我不止一个变量,我有一百个,一千个变量,那么每一个变量我都只能一个一个记下来,这样,其实不是很好

但是现在我们有了进程地址空间中的区域划分,比如你这个变量是一个常量,是一个变量,是一个什么什么变量,你就放在对应的空间里面

这样我们下次要找的话,你这个变量就一定在某一段区域内,相对来说就好管得多

(当然这只是进程地址空间的其中一个好处)

我们来看看内核是怎么写的:

本质上,区域的划分就是存在PCB(task_struct)中的一个struct变量(mm_struct)中的一个个字段,仅此而已

如何理解进程地址空间

假如你是一个富豪,你有10亿美金的财产,现在你有五个私生子

你对每一个私生子都说,你有10个亿,等我不在了这钱全是你的

那么这时,每一个私生子都会想着,富豪只有他 / 她一个孩子,这时候你有用钱的需要,你就和富豪说,如果条件可行,那就运行,如果不对劲,那就驳回

对于内存也是,每一个进程都会认为自己面对的内存是完整的物理内存(进程地址空间)

这时候如果想要开辟物理空间了,那就提交申请给内存,这时候内存就会帮你开辟空间并将结果返回给你

意义是什么

第一、我们能保证进程之间是互相独立的

第二、能有效保护内存,如果说进程中有越界行为,他是碰不到内存的,在虚拟地址空间这里就被驳回了

第三、简化内存管理,进程看到的是连续的虚拟地址空间,实际物理内存可以零散分布(通过页表映射)

第四、高效的进程切换,比如10个进程运行同一程序,代码段只需一份物理内存,通过页表映射到各进程的相同虚拟地址

等等,还有很多原因这里就不一一列举了

越界访问的本质

现在再来看这个问题,就明朗多了

首先我们的变量地址都是被放在页表中一一映射的

现在我们突然来了一个不在这里面的地址,也就是越界访问

那么在页表里面查不到对应的信息,那么就会发现这个是错的,那么系统自然就会将这个请求直接驳回,然后执行某些操作,比如将这个进程直接kill掉,太危险了

进一步理解写时拷贝

首先我们还需要引入一个概念,那是和页表有关的,其实我们前面也学过,就是权限

是的,页表里面也是有权限的

所以我们现在看回这么一串代码:char* a = "hello world";

在我们之前的认知里,他是不能被修改的,因为他是一个常量

那么现在再来看,为什么不能修改?这是因为页表里面的权限,就直接设置了这个变量是只读的,如果你要写,那就直接驳回请求,所以我们才没办法修改

那么现在再来看看写时拷贝

首先,我们一开始所有的变量都是只读的

但是今天我们有一个变量G_VAL,现在我们对他进行修改,这时候就发生错误了

但是,操作系统面对错误之前,还会干一件事情,那就是先检查:

1. 是不是数据之前没放进物理内存里面(缺页中断)

2. 是否是需要写时拷贝

3. 异常处理

说实话这个是非常厉害的,现在我们的系统识别到了,你是想写时拷贝,所以就给你开空间,变页表等等,这也就是我们所谓写时拷贝的本质了

重谈 fork 返回值

现在我们再来看fork的返回值,相信你会变得非常熟悉:

来看这张图,里面的 id 不就是一个变量吗,在fork的逻辑中,当子进程被创造出来的时候,数据拷贝自原有的父进程

接着就是父进程id的值给一份给子进程

但是这个时候fork函数要return了,本质上,这就是写时拷贝

所以物理内存中又开辟了一段空间,给一个名字同样叫做id的变量放进了不同于另一个id的值

最后进程的页表中,关于物理地址映射的那一部分被修改

至此,我们的fork返回值,为什么可以同时给给两个值给 “同一个” 变量的话题,就讲完了

结语

这篇文章到这里就结束啦!!~( ̄▽ ̄)~*

如果觉得对你有帮助的,可以多多关注一下喔


http://www.hkcw.cn/article/xtKHCCrjOe.shtml

相关文章

foundationpose位姿检测环境搭建与数据集制作

foundationpose环境搭建数据集制作 注:本教程为在未知明确方法的探索步骤记录,由于时间原因未做整理,可能有不必要步骤,建议先看完整篇文章理清思路在动手制作 创建数据集 保存RGB和Depth图像: 使用data_collect.py脚本来保存R…

某乎x-zse-96 破解(补环境版本)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、总体概述二、请求分析分析请求流程三、逆向分析总结一、总体概述 本文主要实现某乎x-zse-96 破解(补环境版本),相关的链接: https://www.zhihu.com/search?type=content&q=%25E7%258…

智慧物流园区整体解决方案

该智慧物流园区整体解决方案借助云计算、物联网、ICT 等技术,从咨询规划阶段介入,整合供应链上下游资源,实现物流自动化、信息化与智能化。方案涵盖智慧仓储管理(如自动化立体仓储系统、温湿度监控)、智慧物流(运输管理系统 TMS、GPS 监控)、智慧车辆管理(定位、调度、…

车载诊断架构SOVD --- 车辆发现与建连

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…

基于 OpenObserve 的轻量级分布式日志存储和追踪方案

一、OpenObserve 介绍 OpenObserve 是一个基于 Rust 开发的开源云原生可观察性平台,专为处理海量数据(如日志、指标和追踪数据)而设计,具有高性能、低成本和易用性等特点。 核心功能和特点: 低成本存储:…

python分配方案数 2023年信息素养大赛复赛/决赛真题 小学组/初中组 python编程挑战赛 真题详细解析

python分配方案数 2023全国青少年信息素养大赛Python编程挑战赛复赛真题解析 博主推荐 所有考级比赛学习相关资料合集【推荐收藏】 1、Python比赛 信息素养大赛Python编程挑战赛 蓝桥杯python选拔赛真题详解 蓝桥杯python省赛真题详解 蓝桥杯python国赛真题详解 2、Py…

【后端高阶面经:架构篇】52、微服务架构:微服务是银弹吗?

一、单体架构的困境:微服务诞生的背景 (一)巨石应用的五大痛点 开发效率低下 单体应用WAR包体积可达数百MB,单次全量编译耗时超30分钟,即使修改一行代码也需重新构建整个项目。案例:某电商早期单体应用包含10万行代码,每次发布需协调15个团队,合并冲突处理耗时占比达4…

C57-断言函数assert

一 基本语法 1. 作用 调试工具&#xff1a;用于运行时检查条件是否成立&#xff0c;若失败则终止程序并报错&#xff08;文件名、行号、条件&#xff09;。 2. 语法 #include <assert.h> assert(condition); // condition为假时触发断言3. 行为 条件为真&#xff1…

免费文本转语音工具体验:祈风TTS使用

简介&#xff1a;语音生成的另一种方式 现在很多人通过视频记录生活&#xff0c;表达观点。拍摄剪辑不难&#xff0c;配音成了常见难题。部分人对自己的声音不够自信&#xff0c;也有人在特定场景下不便出声。文本转语音工具可以成为解决方案。 常见的TTS&#xff08;Text To…

Redis持久化机制详解

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

Mistral 推出全新开发者平台Agents API

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

融智学三阶进化模型的全要素可视化解析

摘要&#xff1a;本文提出一种三阶进化模型&#xff0c;通过可视化图表与数学公式阐述人类智慧与人工智能的融合路径。研究构建Mermaid流程图展示"人类智力→形式化智慧→通用AI→超级AI→人机协同"的演进过程&#xff0c;并引入道函数$f_{\mathrm{Tao}}(\mathrm{Ob}…

颠覆传统!单样本熵最小化如何重塑大语言模型训练范式?

颠覆传统&#xff01;单样本熵最小化如何重塑大语言模型训练范式&#xff1f; 大语言模型&#xff08;LLM&#xff09;的训练往往依赖大量标注数据与复杂奖励设计&#xff0c;但最新研究发现&#xff0c;仅用1条无标注数据和10步优化的熵最小化&#xff08;EM&#xff09;方法…

simulink mask、sfunction和tlc的联动、接口

这里全部是讲的level2 sfunction&#xff08;用m语言编写&#xff09;&#xff0c;基于matlab 2020a。 1.mask的参数操作 1&#xff09;mask通过set_param和get_param这2个函数接口对mask里面定义的Parameters&Dialog的参数的大部分属性进行读写&#xff0c;一般是Value值…

【数据结构】图的存储(邻接矩阵与邻接表)

图的存储结构 因为图中既有节点&#xff0c;又有边(节点与节点之间的关系)&#xff0c;因此&#xff0c;在图的存储中&#xff0c;只需要保存&#xff1a;节点和边关系即可。 节点保存比较简单&#xff0c;只需要一段连续空间即可&#xff0c;那边关系该怎么保存呢&#xff1…

C++修炼:unordered_map和unordered_set的使用和封装

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…

Centos环境下安装/重装MySQL完整教程

目录 一、卸载残留的MySQL环境&#xff1a; 二、安装MySQL&#xff1a; 1、下载MySQL官方的yum源&#xff1a; 2、更新系统yum源&#xff1a; 3、确保系统中有了对应的MySQL安装包&#xff1a; 4、安装MySQL服务&#xff1a; 5、密钥问题安装失败解决方法&#xff1a; …

【机器学习基础】机器学习入门核心算法:决策树(Decision Tree)

机器学习入门核心算法&#xff1a;决策树&#xff08;Decision Tree&#xff09; 一、算法逻辑1.1 基本概念1.2 算法流程 二、算法原理与数学推导2.1 特征选择指标信息熵&#xff08;ID3算法&#xff09;信息增益&#xff08;Information Gain&#xff09;信息增益率&#xff0…

基于晶体塑性有限元(CPFEM)的钛合金圆棒拉伸过程模拟

作者&#xff1a;辞殇 关键词&#xff1a;CPFEM&#xff1b;钛合金&#xff1b;单轴拉伸&#xff1b;织构极图&#xff1b;孪晶 晶体塑性有限元是一种结合了晶体塑性理论和有限元方法的数值模拟技术‌。这种方法考虑了晶体材料的各向异性、滑移系统的开动和相互作用、以及变形…

开源是什么?我们为什么要开源?

本片为故事类文章推荐听音频哦 软件自由运动的背景 梦开始的地方 20世纪70年代&#xff0c;软件行业处于早期发展阶段&#xff0c;软件通常与硬件捆绑销售&#xff0c;用户对软件的使用、修改和分发权利非常有限。随着计算机技术的发展和互联网的普及&#xff0c;越来越多的开…