【Linux】进程理解与学习Ⅳ-进程地址空间

环境:centos7.6,腾讯云服务器
Linux文章都放在了专栏:【 Linux 】欢迎支持订阅 🌹
相关文章推荐:
【Linux】冯.诺依曼体系结构与操作系统

【Linux】进程理解与学习Ⅰ-进程概念

浅谈Linux下的shell--BASH

【Linux】进程理解与学习Ⅱ-进程状态

【Linux】进程理解与学习Ⅲ-环境变量

前言

在C/C++阶段对于内存分布相关知识我们耳熟能详。知道 内存空间的划分是为了更好的管理和使用空间。就比如说栈区存放局部变量、静态区存放静态全局变量等。但是,我们这里的空间真的指的是
实际的物理空间吗?换句话来说,我们真的了解该空间吗?本次章节将对此进行探讨。

进程地址空间

前文回顾

  • 首先,我们先来回顾一下,在指针阶段我们学习了,内存被划分为一个一个内存单元,每一个单元的大小为1字节。而每一个内存单元都有自己的编号,从0-0xFFFFFFFF。这里的编号就是我们所说的地址。而我们所说的指针就是这一个个的编号,即指针就是地址。不过这里的地址真的是物理意义上的地址吗

进程地址空间

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

 #include<unistd.h>
 #include<stdlib.h>
 #include<sys/wait.h>
 //定义全局变量
 int tmp=100;
 int main()
 {
   //fork创建子进程
   pid_t id=fork();
   if(id == 0)
   {
     //child
     //对全局变量做修改
     tmp+=100;
     printf("子进程:tmp:%d,&tmp:%p\n",tmp,&tmp);
     exit(1);
   }
   //father
   waitpid(id,NULL,0);
   printf("父进程:tmp:%d,&tmp:%p\n",tmp,&tmp);
   return 0;
 } 

对于此现象,我们在前文也知道了,这是由于进程的独立性子进程在对数据进行修改时,会触发写时拷贝所造成的。但是,假如这里的地址是物理地址的话,同一块地址处却有不同的值,这肯定是不现实的。★因此,我们可以得出这样的结论

  • 我们在语言层面所看到的地址栈区、堆区、静态区...),并不是真正意义上的物理地址(因为假如是物理地址,就不会出现同一个地址却有不同的值)。

  • 那么这种非物理的地址叫什么呢?在Linux中我们称之为虚拟地址/线性地址

  • OS则是将虚拟地址转化为物理地址(如何转化后面会讲到)

如何理解进程地址空间?

首先我们要知道,什么是进程地址空间?

  • 实际上进程地址空间就是操作系统喂给进程的一块“饼”,OS会跟每个进程说,你们有4G的内存空间(栈区、堆区、静态区...)可以使用,但实际上,只有当进程需要用的时候,OS才会分配空间给进程。

举个例子来说,就好比一位富翁,对他的几个儿子说,我的10亿的资产都是你们的。此时儿子心里就会觉得:我有10亿资产可以使用。但实际上富翁并不会直接就是给儿子10亿资产,儿子也不会直接拿到10亿资产。但是假如说,儿子要拿1w元买东西,富翁还是会给儿子·的。此时给的1w才是真正意义上实际的。

接下来谈一谈OS如何管理我们所说的进程地址空间(即我们所说的栈区、堆区等)?

  • 答:先描述,再组织。实际上我们所说的进程地址空间本质上是一个内核数据结构struct_mmstruct{}。在该结构体里存在着大量的_start_end用来表示每一个区域各自的边界值。

  • 就比如说:堆区的区域范围为[heap_start,heap_end]。而对进程地址空间中各个区域的调整,实际上就是转换为了调整各个区域对应的_start与_end。

物理空间与虚拟空间

既然我们所说的地址都是虚拟地址,那么真正的物理地址在哪里呢???虚拟地址与物理地址之间又有什么关系呢?

  • 实际上,OS会通过页表,以及MMU的存在,我们所谓的虚拟地址与物理地址之间建立一种映射关系,通过虚拟地址映射后的地址,可以寻到物理地址。同时可以将物理地址,经过页表映射虚拟地址返回给进程。就好像下面这样:

写时拷贝

我们来解释一下最开始的现象:为什么父子进程的tmp地址相同,但结果不同呢?

  • 实际上当一方进程想要对数据进行修改时,会触发写时拷贝将物理空间原有的指向内容拷贝出一份,在拷贝后的那里进行对数据的修改,并将拷贝后的物理地址重新与原有的虚拟地址建立映射关系:

  • 因此我们也可以这么来说,所谓的写时拷贝,实际上是操作系统的一种赌博式行为。OS赌你不会对数据进行修改,所以当各个进程不对数据进行修改时,多个进程在此时访问同一个数据,实际上该数据所在的物理空间是同一块只有当进程对数据进行修改时OS才会另外开辟空间,并将原物理空间的内容拷贝进去,重新建立一种映射关系。并满足进程对数据的修改。而这也是进程独立性的一种重要表现,即多个进程互不影响。

而写时拷贝这种“赌博行为”机制的好处就在于:

  • 1、减少了物理空间的使用(多个进程的数据访问的是同一块空间)

  • 2、减少了写时拷贝的次数(只有需要修改数据时才会发生拷贝,否则不会),提高了运行效率(写时拷贝一定会调用拷贝构造进行深拷贝,会有一定效率的影响)。

拓展:为什么存在进程地址空间?

一、防止地址随意访问,保护物理内存与其它进程

实际上,在最开始的时候,还没有虚拟地址这种概念。早期的进程是直接与物理内存打交道。但是可能会存在野指针问题:

  • 假如我们写的程序中存在野指针,这就造成了对物理内存越界访问,就有可能会影响到其它进程。但是现在有了虚拟地址,进程不会与物理内存直接打交道,OS就相当于多了一道屏障,对于进程发出的不合理的请求,OS可以拒绝。

(就好比富翁不会直接把10亿元直接给儿子,因为儿子可能一会儿就败光了,而是告诉儿子,你有10亿元的资产可以使用,我帮你保管,你需要时再给你。这样当儿子发出不合理的使用时,富翁可以直接拒绝)

二、将进程管理与内存管理进行解耦合
  • 我们先来谈一谈malloc的本质,实际上我们平常使用malloc开辟一块空间时,OS并不是说直接给我们开辟出一块空间给我们。而是只有当我们需要这块空间时,OS再开辟空间供我们使用。

  • 这是因为OS不允许任何空间的浪费而当我们malloc之后,使用之前,这块空间处于一种闲置状态,OS是绝对不允许的。这就是所谓的"缺页中断"

因此对于进程来说,我只需要通过页表映射向内存去要,对于内存来说,我只需要在进程使用空间时提供一块没被使用的空间。这就实现了进程管理与内存管理之间的解耦!

三、让进程以统一的视角,看待自己的代码与数据

实际上虚拟地址的这种策略并不仅仅只有OS才有,我们的编译器也会遵循。也就是说,我们的程序在被编译时,本身内部已经存在了虚拟地址。我们可以输入指令objdump -S 可执行程序的指令,来查看该程序的反汇编,就好像下面这样,这些都是虚拟地址:

也就是说,我们的程序在被加载到内存之前,本身内部就已经有了虚拟地址: 加载到物理内存之后,则天然具有物理地址,然后通过 页表映射,建立与虚拟地址之间的联系。而当CPU进行调度时,通过虚拟地址经过页表映射后,将物理地址的内容加载到CPU运行,此时 CPU内部全都是程序内部已经存在的虚拟地址,再紧接着,CPU通过虚拟地址经过页表寻址到物理地址,并加载到CPU运行...循环以往,直到跑完整个程序。
因此 对于每一个进程来说,我并不需要关心我内部的代码与数据被加载到物理内存的哪一个位置,不管是否物理地址连续有序,都会经过页表映射建立与虚拟地址之间的联系,将物理内存的并不连续有序的物理地址,转化为了虚拟内存中有序的虚拟地址。每一个进程都是如此,将看待物理内存中并不有序的物理地址,经过映射后转化为看待虚拟内存中的有序地址。

end.

生活原本沉闷,但跑起来就会有风!🌹

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[JavaEE]----Spring01

文章目录Spring_day011&#xff0c;课程介绍1.1 为什么要学?1.2 学什么?1.3 怎么学?2&#xff0c;Spring相关概念2.1 初识Spring2.1.1 Spring家族2.1.2 了解Spring发展史2.2 Spring系统架构2.2.1 系统架构图2.2.2 课程学习路线2.3 Spring核心概念2.3.1 目前项目中的问题2.3.…

VN5620以太网测试——环境搭建篇

文章目录 前言一、新建以太网工程二、Port Configuration三、Link up四 Trace界面五、添加Ethernet Packet Builder六、添加ARP Packet七、添加Ethernet IG总结前言 CANoe(CAN open environment)VN5620 :是一个紧凑而强大的接口,用于以太网网络的分析、仿真、测试和验证。 …

面试篇-深入理解 Java 中的 HashMap 实现原理

一、HashMap实现原理 HashMap 的实现主要包括两个部分&#xff1a;哈希函数和解决哈希冲突的方法。 1.哈希函数 当使用 put() 方法将键值对存储在 HashMap 中时&#xff0c;首先需要计算键的哈希值。HashMap 使用 hashCode() 方法获取键的哈希值&#xff0c;并将其转换为桶&…

2023-04-11 无向图的匹配问题

无向图的匹配问题 之所以把无向图的这个匹配问题放到最后讲是因为匹配问题借鉴了有向图中一些算法的思想 1 最大匹配和完美匹配 二分图回顾 二分图&#xff1a;把一个图中的所有顶点分成两部分&#xff0c;如果每条边的两端分别属于不同部分&#xff0c;则这个图是二分图。更多…

springcloud——gateway功能拓展

目录 1.获取用户真实IP 2.统一跨域配置 3.redis令牌桶算法限流 1.获取用户真实IP 在我们的日常业务中&#xff0c;我们时常需要获取用户的IP地址&#xff0c;作登录日志、访问限制等相关操作。 而在我们的开发架构中&#xff0c;一般我们将服务分为多个微服务&#xff0c;…

Python 进阶指南(编程轻松进阶):一、处理错误和寻求帮助

原文&#xff1a;http://inventwithpython.com/beyond/chapter1.html 请您不要将计算机当成佣人&#xff0c;因为这样会让您常常感觉很烦躁。比如说当计算机向您显示错误消息时&#xff0c;并不是因为您冒犯了它。计算机是我们大多数人都会接触到的最复杂的工具&#xff0c;但归…

HBase高手之路4-Shell操作

文章目录HBase高手之路3—HBase的shell操作一、hbase的shell命令汇总二、需求三、表的操作1&#xff0e;进入shell命令行2&#xff0e;创建表3&#xff0e;查看表的定义4&#xff0e;列出所有的表5&#xff0e;删除表1)禁用表2)启用表3)删除表四、数据的操作1&#xff0e;添加数…

【HAL库】BMP180气压传感器+STM32,hal库移植

BMP180气压传感器STM321 导入.c.h文件&#xff08;不再赘述&#xff0c;详细见LED部分&#xff09;2 Cubemx配置3 修改 .h 文件4 测试将BMP180从标准库移植到HAL库。模拟IIC。 极简工程代码如下&#xff1a; https://github.com/wyfroom/HAL_BMP180 该份代码硬件配置&#xff…

Oracle_EBS_核心功能(MFG)(1)

INV: Items参考《深入浅出Oracle EBS之核心功能&#xff08;DIS&#xff09;》。canca INV: Transactions基本库存事务处理参考《深入浅出Oracle EBS之核心功能&#xff08;DIS&#xff09;》。canca BOM: Bills of Material物料清单应用&#xff1a;Bills of Material 职责&am…

day-004-链表-两两交换链表中的节点、删除链表的倒数第N个节点、链表相交、环形链表II

两两交换链表中的节点 题目建议&#xff1a;用虚拟头结点&#xff0c;这样会方便很多。 题目链接/文章讲解/视频讲解 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* Li…

阿里9年测试经验告诉你:作为一名年薪40w自动化测试需要具备那些能力

前言 前段时间张同学问我说&#xff1a;我已经功能测试2年多了&#xff0c;在功能测试的阶段中也一直在自学自动化测试&#xff0c;有了一定的代码基础还学习了很多的工具&#xff0c;问题是我不知道自动化测试到底需要具备什么样的能力。 我相信有很多小伙伴也是在思索这个问…

计算机组成的基本认识

计算机——> 数值计算——> 处理电信号——> 基本单元&#xff08;逻辑元件&#xff09; 电子管——> 晶体管——>中小规模集成电路 ——>大规模&#xff0c;超大规模集成电路 机器字长&#xff1a;计算机一次整数运算所能处理的二进制位数 解析存储器中的程…

这家年销售额309亿的Tier 1,要谈一场千亿新生意

跨入2023年&#xff0c;智能汽车软件赛道更热闹了。 相较于传统汽车开发模式&#xff0c;软件属于分布式ECU工程开发的一部分&#xff0c;由一级供应商作为黑盒提供&#xff0c;软件开发成本等被认为是硬件系统成本的一部分&#xff0c;没有实现单独定价。 如今&#xff0c;“…

如何在windows/linux下启动OpenOffice

上面一篇文章使用openOffice来实现预览word、excel、pdf、txt等的功能时&#xff0c;发现openOffice没有启动&#xff0c;也怕有些同学安装后不会启动&#xff0c;所以便写下这一篇文章&#xff0c;来为大家说明如何启动openOffice&#xff0c;上一篇讲的如何下载安装openOffic…

2.5 函数的微分

思维导图&#xff1a; 学习目标&#xff1a; 我认为学习函数的微分需要以下几个步骤&#xff1a; 熟练掌握导数的定义和基本性质&#xff0c;包括求导法则和高阶导数的概念。学习一些重要的函数的导数&#xff0c;例如多项式函数、三角函数、指数函数和对数函数等。这些函数的…

CSDN——Markdown编辑器——官方指导

CSDN——Markdown编辑器——官方指导欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表…

Node.js -- http模块

1. 什么是http模块 在网络节点中&#xff0c;负责消费资源的电脑&#xff0c;叫客户端&#xff1b;负责对外提供网络资源的电脑&#xff0c;叫做服务器。 http模块是Node.js官方提供的&#xff0c;用来创建web服务器的模块。通过http模块提供的http.createServer()方法&#…

手写一个Promise

Promise Promise是一个对象&#xff0c;用于解决异步变成的问题&#xff0c;由传统的异步回调为服务端立即调用优化为使用者者掌握回调主动权。 比如传统的JSONP&#xff0c;如下&#xff0c;在请求路由里添加回调函数&#xff0c;由接收请求的一方来调用请求&#xff0c;使用…

kafka笔记

消息队列 场景模式基础架构发送原理异步发送同步发送分区生产者提高吞吐量&#xff1a;数据可靠性ack应答数据重复幂等性事务数据有序数据乱序broker工作流程follower故障leader故障数据查找文件清除高效读写消费者流程消费者组初始化分区分配策略自动提交offset手动提交指定位…

Kubernetes调度器源码学习(一):调度器工作原理、调度器启动流程、调度队列

本文基于Kubernetes v1.22.4版本进行源码学习 1、调度器工作原理 1&#xff09;、调度流程 kube-scheduler的主要作用就是根据特定的调度算法和调度策略将Pod调度到合适的Node节点上去&#xff0c;是一个独立的二进制程序&#xff0c;启动之后会一直监听API Server&#xff0…