Linux进程理解【程序地址空间】

news2024/11/27 8:46:27

Linux进程理解【程序地址空间】

文章目录

  • Linux进程理解【程序地址空间】
  • 1. 话题引入
  • 2. 进程地址空间
    • 2.1 虚拟地址
    • 2.2 写时拷贝
  • 3. 知识扩展

我们先来看看C/C++程序地址空间的分布图

如此多区域的划分是为了更好的使用和管理空间,但是真实的内存空间也是按照图上的地址空间这样划分的吗?其实并不是,那么这样划分的不是内存是什么呢?真正的内存又在哪呢?且带着这些问题,本文将对这些疑惑一一解答

1. 话题引入

我们定义一个变量,创建父子进程共同使用这个变量,并子进程中对其做出修改,来看看现象

int main()
{
  pid_t id = fork(); //获取返回值
  assert(id != -1);  //创建失败的情况
  int num = 100;

  if(id == 0) //子进程
  {
    num += 12; //子进程中改变num的值
    printf("我是子进程, 我的PID是: %d,PPID是: %d, num = %d, num的地址: %p\n", getpid(), getppid(), num, &num);
  }
  else if(id > 0) //父进程
  {
    printf("我是父进程, 我的PID是: %d,PPID是: %d, num = %d, num的地址: %p\n", getpid(), getppid(), num, &num);
  }

  return 0;
}

我们运行发现,在同一块地址空间,读到了不同的值

分析:

  • 物理地址是唯一的,如果这里表示的是物理地址的话,不可能在同一个变量的地址上,读取到两个不同的值,所以这个地址一定不是物理地址

结论:

  • 子进程修改变量值的时候,发生了写时拷贝机制
  • 语言层面用的地址,不是物理地址,而是被称为虚拟地址或者线性地址

2. 进程地址空间

所以上面空间分布图其实是虚拟空间的分布图,下面我们来看看真实的空间分布图

2.1 虚拟地址

下面我们结合两个小故事来帮助大家理解

小明今年初三,妈妈每个周末都会给他布置作业,临近期末考试,妈妈对小明说,如果他考进了年级前十下学期就把周末的作业免了,小明高兴极了,更加努力的学习,真的取得了年级前十。马上下学期开学了,到了周末妈妈又给小明布置了作业,小明有苦说不出,只能继续照做。

  • 故事中妈妈给小明画了一个免除作业的饼,类比一下,这个饼就是虚拟地址空间,而小明就是一个进程,妈妈就是操作系统,说来虚拟地址空间就是操作系统给进程画的饼,而妈妈在下学期周末又布置的作业就是内存了
  • 妈妈为了激励小明学习是要管理这张饼的,也就对应着操作系统需要管理击进程地址空间,也是用了先描述,再组织的方式,而虚拟地址空间本质就是操作系统中的一个内核数据结构 mm_struct

开学第一天小沸和小美被老师安排成了同桌,小沸是个有些邋遢的男生,而小美是个很爱干净的女生,小美对于小沸很是嫌弃,当即就在桌子上画清了三八线,对小沸说,桌子三分之二都是我的,你只能在线那边的三分之一,小沸听了虽然有些伤心,但还是笑眯眯的答应了。

  • 在小美画的三八线两侧两人井水不犯河水,这里区域划分的本质就是对线性区域指定startend来完成区域划分

在mm_struct结构体中,也是如此划分,通过对边界值的调整,还可以做到不同区域的增长

mm_struct
{
	//代码区划分
	unsigned long code_start;
	unsigned long code_end;

	//堆区划分
	unsigned long heap_start;
	unsigned long heap_end;

	//栈区划分
	unsigned long stack_start;
	unsigned long stack_end;
	
	// ......
}

虚拟地址空间,加上页表 + MMU机制,通过寻址的方式,进行物理内存的访问

如何理解这个地址空间是线性连续的呢?

  • 在使用visual studio进行调试时,打开内存会发现我们的地址空间中的地址是用16进制表示的,32位计算机下范围是[0x00000000, 0xFFFFFFFF],有4G的空间大小

  • 地址是多少不重要,关键是地址具有唯一性,不能发生冲突,每个地址值对应的就是一个字节。所以因为表示地址数字是连续的,所以这里说地址空间是线性连续的

2.2 写时拷贝

写时拷贝

  • 多个进程在访问同一个数据时,会指向同一块空间
  • 当发生数据改写行为时,再重新开辟空间进行改写,这就是写时拷贝机制
  • 写时拷贝其实是一种赌bo行为,OS会赌你不会对数据做出修改,来提高效率

了解了以上,我们就能对最开始的问题:为什么同一块地址空间,会读到了不同的值做出更好的解释了

  • 父子进程有着一模一样的mm_struct,变量对应的虚拟地址,通过页表 + MMU的转换,指向同一块内存空间
  • 子进程对变量的改写,为了不影响父进程,此时OS会触发写时拷贝机制,在内存中重新开辟一块空间拷贝变量值,再来对其进行改写,父子进程的mm_struct并不改变,改变的是物理内存空间

3. 知识扩展

没有虚拟地址空间,操作系统是如何工作的

  • 早期在没有虚拟地址空间的时候,是直接在物理地址上进行数据读写的,当我们多个进程加载到内存时,其中有个进程时访问地址的操作,然后给到CPU,CPU返回给这个进程一个不是本进程而是其他进程的地址,这样假如我们本进程要进行写入或者删除的操作,这样就会影响到了其他进程,这样就无法保证进程的独立性

于是大佬们就引入了虚拟地址空间,加上页表 + MMU机制,通过寻址的方式,进行物理内存的访问,体现了不菲的价值

  • 防止地址随意访问,保护物理内存和其他进程
  • 将进程管理和内存管理进行解耦合
  • 让进程以统一的视角看待代码和数据

再来看看申请内存malloc的本质

  • 我们向操作系统申请空间,操作系统是你在需要的时候才会给你,而不是立马给你,因为操作系统是不允许任何的浪费或者不高效的行为
  • 在你申请成功之后和在你使用之前,这块空间有一段的闲置状态,操作系统为了不让空间浪费,首先是在虚拟地址空间申请空间,然后将对应的虚拟地址放进页表,但是没有映射处物理地址,物理内存上也没有申请空间,这种行为就叫做缺页中断

进阶理解虚拟地址空间

  • 程序在被编译的时候,没有被加载到内存中,那么程序内部是有地址的
  • 源代码在被编译的时候,就是按照虚拟地址空间的方式进行的,对代码和数据就已经编好了对应的编制。不要认为虚拟地址这样的策略只会影响OS,它也会让编译器遵守对用的规则
  • CPU中读取到的数据对应的地址还是虚拟地址

Linux进程理解—程序地址空间,到这里就介绍结束了,本篇文章对你由帮助的话,期待大佬们的三连,你们的支持是我最大的动力!

文章有写的不足或是错误的地方,欢迎评论或私信指出,我会在第一时间改正

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

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

相关文章

nginx的下载与安装

https://nginx.org/en/download.html 下载地址(我下载的是1.20.2) 1、首先保证可以连接外网 2、将包拖入opt/nginx 3、安装gcc环境 (如果出现问题可以参考https://www.cnblogs.com/lzxianren/p/4254059.html) yum -y install gc…

你还在手动对比代码差异?这些高质量工具太香了

B站|公众号:啥都会一点的研究生 我发现相当一部分初学者(甚至搬砖多年的老同志)在对比文件差异的时候居然还是 观察法 文本内容少还凑活能用,成百上千行的时候把眼睛累坏了不说,关键还容易漏信息 接触的人与事多了会…

volatile的可见性探讨

我跟volatile修饰对象和数组能保证其内部元素的可见性?一文的作者有类似的疑惑,按语义,volatile修饰数组时,只是保证其引用地址的可见性,可为什么给数组加了volatile之后,似乎单个数组元素也有了可见性&…

Android Glide同步阻塞方式submit获得Bitmap,kotlin

droid Glide同步阻塞方式submit获得Bitmap,kotlin 需要放入后台线程,不能在主线程。 Android Glide预加载preload ,kotlin_zhangphil的博客-CSDN博客【代码】Android Paging 3,kotlin(1)在实际的开发中,虽然Glide解决了…

AC+AP 旁挂式连接配置(华为)

AR1路由器配置 # interface GigabitEthernet0/0/0 ip address 10.1.30.1 255.255.255.0 ip route-static 10.1.20.0 255.255.255.0 10.1.30.2 # LSW1核心交换机 # dhcp enable vlan batch 10 20 30 interface Vlanif20 ip address 10.1.20.1 255.255.255.0 dhcp select in…

nacos启动多个集群

nacos启动多个集群,只需要改动集群的名称,然后再次实例服务即可。

Vue3正式发布那么久了,你认识Pinia了吗?

个人简介 👀个人主页: 前端杂货铺 🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…

一个无经验的大学毕业生,可以转行做软件测试吗?

先说答案,一个无经验的大学毕业生,可以转行做软件测试。 首先什么人会提出这个问题?应该是个大学生,而且肯定不是计算机系毕业的,甚至都不可能是一个工科生。因为哪怕是工科毕业的学生,大学期间最少也学习过C语言编程…

数据结构(王道)——栈的应用

一、括号匹配检查 思路: 算法结构: 代码实现: 算法思路总结: 二、表达式求值 中缀、后缀、前缀表达式: 中缀转后缀表达式 三、栈在递归当中的应用 递归在斐阶乘的应用 缺陷:递归层数过多的话可能会导致栈溢…

小程序MobX创建store并实现全局数据共享

查看小程序根目录中是否存在package.json文件 在项目根目录运行cmd 没有package.json文件输入npm init -y初始化一下,初始化一个包管理 安装MobX npm install --save mobx-miniprogram4.13.2 mobx-miniprogram-bindings1.2.1 小程序菜单栏工具–构建npm 根目录创建store文…

单目相机标定、图像校正、单目位姿估计、差值法检测移动物体、稠密光流法跟踪移动物体

目录 1、单目相机标定 2、图像校正 3、单目位姿估计 4、差值法检测移动物体 5、稠密光流法跟踪移动物体 1、单目相机标定 //单目相机标定 int test1() {//读取所有图像vector<Mat> imgs;string imageName;ifstream fin("F:/testMap/calibdate.txt");while(…

AtCoder Regular Contest 159

B - GCD Subtraction 题意&#xff1a; 给定两个正整数 A , B A,B A,B&#xff0c;给定一个操作&#xff1a;令 g g c d ( A , B ) ggcd(A, B) ggcd(A,B)&#xff0c;令 A A − g , B B − g AA-g, BB-g AA−g,BB−g。问最少经过多少次操作之后其中一个数变为0. 思路&…

APPScan介绍以及安装方式【附带链接】

AppScan介绍和安装 请务必下载绑定的链接&#xff0c;避免环境错误 1.简介 Appscan 10中文版是是全新网络安全漏洞扫描软件&#xff0c;软件可以直接可以对OS命令、SSRF和XXE攻击等漏洞进行检测&#xff0c;使得漏洞检测更加容易&#xff0c;提高漏洞的扫描效率。软件同时支…

[LeetCode周赛复盘] 第 354 场周赛20230716

[LeetCode周赛复盘] 第 354 场周赛20230716 一、本周周赛总结6889. 特殊元素平方和1. 题目描述2. 思路分析3. 代码实现 6929. 数组的最大美丽值1. 题目描述2. 思路分析3. 代码实现 6927. 合法分割的最小下标1. 题目描述2. 思路分析3. 代码实现 6924. 最长合法子字符串的长度1.…

Go语言之重要数组类型map(映射)类型

通过切片&#xff0c;我们可以动态灵活存储管理学生姓名、年龄等信息&#xff0c;比如 names : []string{"张三","李四","王五"} ages : []int{23,24,25} fmt.Println(names) fmt.Println(ages)但是如果我想获取张三的年龄&#xff0c;这是一个…

概率论的学习和整理17:EXCEL的各种期望,方差的公式

目录 1 总结 1.1 本文目标总结方法 1.2 总结一些中间关键函数 2 均值和期望 2.1 求均值的公式 2.2 求随机变量期望的公式 2.3 求随机变量期望的朴素公式 3 方差 3.1 确定数的方差 3.2 统计数的方差公式 3.3 随机变量的方差公式 3.4 EXCEL提供的直接计算方差的公式 …

Ant Design Vue组件,a-select标签

a-select标签是组件里的选择框&#xff0c;具体使用可以查看官网&#xff0c;这里记录一下在使用中遇到的问题。 最近在做项目的时候有一个需求在 a-modal 标签中加入 a-select 标签&#xff0c;a-modal 是模态对话框&#xff0c;意思就是在模态对话框里面添加选择框&#xff0…

Cglib 动态代理实现

每天看看新东西,心情也要好上许多 问题 cglib是如何实现动态代理的cglib如何支持类的代理cglib和jdk的动态代理有什么区别 使用方式 cglib不属于jdk的一部分,因此要使用需要先引入相应的包,maven依赖如下 <dependency><groupId>cglib</groupId><artif…

TortoiseGit 入门指南09:合并

前面章节讲了 分支&#xff0c;提到一种常用的工作流&#xff1a;将默认分支&#xff08;master&#xff09;设置为主分支&#xff0c;保存最新的、随时可以发布的版本&#xff0c;所有的新特性、BUG都在另一个称为特性分支上增加或修改&#xff0c;然后在一个合适点&#xff0…

Ubuntu下搭建Redis主从集群

目录 准备实例和配置 开启主从关系 测试配置 搭建的主从集群结构&#xff0c;只有主服务器与客户端进行写操作&#xff0c;通过主从同步数据&#xff0c;从服务器向客户端提供读操作 共包含三个节点&#xff0c;一个主节点&#xff0c;两个从节点。 这里我们会在同一台虚拟机…