Linux:进程虚拟地址空间

程序地址空间

  1. 理解程序地址空间图
    请添加图片描述
      答:需要知道整体地址从低到高,栈地址较大,而堆较小,且栈向下增长,即地址从高到低使用。堆向上增长,地址从低到高,两者相邻但空着很多。此外,全局变量在下面。

  2. 程序的空间地址是什么?内存吗?
    做如下实验:
    a. vim 编写代码
    请添加图片描述
    b. 运行查看
    请添加图片描述
    c. 发现父子值不一样,但是打印的地址一样。相同地址为什么会读到不同值?我们知道写时拷贝使得父子进程中即使发生改变量,也不会影响别的进程,但为什么写时拷贝后,还是显示相同地址。如果是物理地址,不可能在同一个地址读到到不同值。
      答:原因是程序中运行得到的地址是虚拟地址,不是物理地址。虚拟地址可以映射去物理地址。

这里,引出了进程虚拟地址空间,本质没有程序地址空间。

进程虚拟地址空间

引言:以后要明白,没有习惯上说的C/C++程序地址空间说是内存,实际上只存在进程虚拟地址空间。

  1. 进程是否需要地址空间?且操作系统是否需要管理地址空间?
      答:每个进程都要有一个地址空间,且都认为自己在独占物理内存。系统中存在大量系统空间要分配给进程,所以操作系统必须要管理地址空间。

  2. 操作系统如何管理进程虚拟地址空间?
      答:先描述,再组织。如何先描述?操作系统管理进程除了生成PCB:task_struct之外,描述地址空间还使用结构体mm_struct来描述对应地址空间。在内核中是一个数据结构类型,是具体的地址空间变量。其中mm_struct包含合适分配、如何分配等信息。总之,操作系统管理进程会生成PCB的task_struct(任务结构体)描述进程还需mm_struct(描述地址空间)。

  3. 谈谈对每个进程的mm_struct的理解
      答:操作系统给每个进程画大饼,每个进程的mm_struct地址空间给4GB(32位)。但是进程实际并不能全部使用这4G。它内部会规定每一部分的起始和结束。内部有不同区间,且对区域做了划分。如下所示:
    请添加图片描述
      虽然只有start和end,但每个进程都可以认为mm_struct代表整个内存。且所有地址为0x000…000~0xFFF…FF。
      总之,每个进程都认为地址空间的划分按着4GB做划分的。【但实际它用不上全部4GB】。因为如上图的start->end都做好了区域限定。
    且以上,也是每个进程独立的原因,每个进程有自己独立的地址空间。

  4. 既然用虚拟地址,那么操作系统如何通过虚拟地址得到的代码和数据?
      答:通过页表。页表是操作系统为维护每个进程的一张表。这张表中左侧是虚拟地址,右侧是物理地址。操作系统通过虚拟地址转为物理地址。页表可以理解为是映射表,也就是哈希表。此外,MMU是一种集成在CPU中的硬件,MMU专门负责查页表。
    请添加图片描述

  5. 观察如下代码,为何不可写?
    请添加图片描述
      答:操作系统给你的权限只有r。页表中有权限,对某些角色不能w。用*str本质是访问虚拟地址,发现页表中的权限不足。
    这种情况的存在,是为了保护物理内存以及各个进程的数据安全。

  6. 地址空间的作用:

  1. 不让进程直接放在物理内存中直接操作可以隔离开其它进程防止错误操作带来的影响,且防止恶意程序。 通过加一层软件层,完成有效对进程操作内存的风险管理,保护物理内存和各个进程的数据安全。如果进程直接放在内存中,A进程的数据可能因为B的不当操作越界操作数据而影响到A。甚至可能会有恶意程序拿到你的秘密数据甚至对其修改做出破坏。所以为了安全,加一个虚拟地址去映射真实物理地址。操作系统利用页表和MMU把虚拟地址转为物理地址。
  2. 将内存申请和内存使用在时间上划分清楚:比如malloc()一块连续空间,但可以先不赋值。所以我们确信可以先申请空间,但不使用。在操作系统角度,如果空间给你,但你不使用,其实可以给的进程先使用。此外,那么操作系统如何知道进程是否在使用地址空间?如果该进程从来没有读写过这片空间,操作系统会认为该进程没有使用过这片空间。等该进程真正要使用这片空间时,会再开辟空间或把别的进程不用的空间给这个进程使用。【当然可能存在无物理空间可分配空间的情况】。这就是缺页中断进行物理内存申请
  3. CPU怎么知道起始代码在哪里?如果不同进程在不同物理地址,每个进程都不一样,所以起始位置不一样,那么还需要维护进程起始地址。CPU调度进程还得找每个进程的起始地址,很麻烦。所以操作系统让CPU每次从固定位置开始读。每个进程都有页表,可以方便映射去该进程的代码和数据所在的物理地址中。使用页表映射使得CPU不用自己去物理地址中寻找代码起始地址,方便CPU。 此外,用映射表的方式可以使得程序的代码和数据可以被加载到物理内存的任意位置。大大减少内存管理的负担。
    总之,**站在,CPU和应用层角度,可以看做进程统一使用4GB空间,每个空间区域的相对位置都比较确定。**操作系统最终这样设计的目的,达到一个目标,每个进程都认为自己是独占系统资源的:每个进程都认为自己可以使用4GB。
  1. 如何理解每个进都认为自己可以使用4GB(32位)空间?
      答:表面上,该进程的代码和数据可以放在整个4GB的任意位置。其实是因每个进程有自己的映射方式。对每个进程,操作系统通过页表、MMU把虚拟地址映射到不同物理地址的的位置。这种统一管理的方式,使得内存管理更加灵活。

  2. 关于父子进程的内存管理:
      答:父子进程的代码是共享的,映射去了同一片物理地址区域,这里存了代码。

  3. 更新印象中的内存划分图:
      答:其实还有命令行参数环境变量等空间。且暂时知道最上面有1G内核空间。下面是用户空间3G。
    请添加图片描述

  4. 进程的退出码是什么?
      答:main函数return值是进程的退出码。Linux每执行完一个命令,都有退出码。因命令行是进程去执行的。且进程的退出场景有正确和不正确。码0代表正确,而!0代表不正确。

  5. shell如何读程序(进程)退出码?
    echo $?:输出最近一次进程退出码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值