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

这篇具有很好参考价值的文章主要介绍了【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】进程理解与学习Ⅳ-进程地址空间

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

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

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

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

如何理解进程地址空间?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

【Linux】进程理解与学习Ⅳ-进程地址空间
三、让进程以统一的视角,看待自己的代码与数据

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

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

end.

生活原本沉闷,但跑起来就会有风!🌹文章来源地址https://www.toymoban.com/news/detail-413107.html

到了这里,关于【Linux】进程理解与学习Ⅳ-进程地址空间的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux之进程(四)(进程地址空间)

    目录 一、程序地址空间 二、进程地址空间 1、概念 2、写时拷贝 3、为什么要有进程地址空间 四、总结 我们先来看看下面这张图。这张图是我们在学习语言时就见到过的内存区域划分图。  下面我们在Linux下看一看内存区域是不是也是这么划分的。 可见在Linux下也是符合上面

    2024年02月04日
    浏览(29)
  • 【Linux】进程周边006之进程地址空间

      👀 樊梓慕: 个人主页  🎥 个人专栏: 《C语言》 《数据结构》 《蓝桥杯试题》 《LeetCode刷题笔记》 《实训项目》 《C++》 《Linux》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.程序地址空间 1.1验证地址空间的排布  1.2利用fork函数观察当子进程修改某个共

    2024年02月04日
    浏览(28)
  • 【Linux】进程>环境变量&&地址空间&&进程调度

    主页: 醋溜马桶圈-CSDN博客 专栏: Linux_醋溜马桶圈的博客-CSDN博客 gitee :mnxcc (mnxcc) - Gitee.com 目录 1.环境变量 1.1 基本概念 1.2 常见环境变量  1.3 查看环境变量方法  1.4 和环境变量相关的命令 1.5 环境变量的组织方式 1.6 通过代码如何获取环境变量 1.6.1 命令行第三个参数 1

    2024年04月15日
    浏览(41)
  • 浅析Linux进程地址空间

    现代处理器基本都支持虚拟内存管理,在开启虚存管理时,程序只能访问到虚拟地址,处理器的内存管理单元(MMU)会自动完成虚拟地址到物理地址的转换。基于虚拟内存机制,操作系统可以为每个运行中的进程创建独享的虚拟地址空间,在这个空间中执行的程序,无法感知

    2024年01月20日
    浏览(29)
  • Linux:进程地址空间

    目录 1.程序地址空间  2.进程地址空间 我们在讲C/C++语言的时候,32位平台下,我们见过这样的空间布局图 我们来验证一下这张图的正确性: 运行结果: 通过观察静态变量的位置,可以认为静态变量就是全局变量,只是静态变量只初始化一次,有作用域的限制。 这里栈区还

    2024年02月04日
    浏览(30)
  • 【Linux】—— 进程地址空间

    序言: 在上篇中,我们讲解了关于进程优先级的概念。本期,我将给大家介绍的是关于进程地址空间的话题。 目录 (一)程序地址空间回顾 (二)代码演示 (三)进程地址空间的引入 总结 我们在学习C/C++语言的时候,大家可能都见过这样的空间布局图: 一个程序有哪些

    2024年02月15日
    浏览(30)
  • Linux--进程地址空间

    1.线程地址空间 所谓进程地址空间(process address space),就是从进程的视角看到的地址空间,是进程运行时所用到的虚拟地址的集合。 简单地说,进程就是内核数据结构和代码和本身的代码和数据,进程本身不能访问物理地址,之时候就需要有一个中间媒介,就是地址空间,

    2024年02月11日
    浏览(29)
  • 【Linux】深挖进程地址空间

    作者简介:დ旧言~,目前大二,现在学习Java,c,c++,Python等 座右铭:松树千年终是朽,槿花一日自为荣。 目标:熟悉【Linux】进程地址空间 毒鸡汤:也许有一天,你发觉日子特别的艰难,那可能是这次的收获特别的巨大。 望小伙伴们点赞👍收藏✨加关注哟💕💕      

    2024年02月03日
    浏览(26)
  • 『 Linux 』进程地址空间概念

    在c/C++中存在一种 内存 的概念; 一般来说一个内存的空间分布包括 栈区 , 堆区 , 代码段 等等; 且内存是 自底向上 (由 0x00000000 至 0xFFFFFFFF ); 以该图为例: 该图即为常见的内存分布图; 正文代码段 正文代码段所存放的数据 一般为函数体的二进制代码 ; 已初始化数据区 已初始化

    2024年02月03日
    浏览(30)
  • 【Linux取经路】初探进程地址空间

    之前在介绍 fork 函数的时候说过该函数返回了两次,至于为什么会返回两次,以及 fork 函数是如何做到返回两次的,在【Linux取经路】揭秘进程的父与子一文中已经做了详细的解释,忘了小伙伴可以点回去看看。在解释一个变量怎么会有两个不同值的时候,当时的说法是由于

    2024年01月21日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包