【Linux进程篇】进程地址空间

【Linux进程篇】进程地址空间

目录

  • 【Linux进程篇】进程地址空间
      • 再次认识空间布局
      • 进程地址空间
      • Linux2.6内核进程调度队列(Linxu进程篇2有涉及)
        • 一个CPU拥有一个runqueue(运行队列)
        • 活动队列
        • 过期队列
        • active指针和expired指针
        • 总结

作者:爱写代码的刚子
时间:2023.10.20
前言:本篇博客是对【Linux进程篇】的收尾,介绍进程地址空间的相关内容。本篇博客研究的背景:kernel 2.6.32 32位平台


再次认识空间布局

【Linux进程篇】进程地址空间_第1张图片

其中:未初始化数据和初始化数据属于静态全局区。

环境变量比命令行参数更靠近高地址

注意:不同芯片平台栈的增长方向可能不同,栈顶指针用esp寄存器存储,同时不管数组在栈区还是堆区,数组的生长方向都是从下往上的(也就是从低地址到高地址的)

  • 验证一(同时不管数组在栈区还是堆区,数组的生长方向都是从低地址到高地址的):

【Linux进程篇】进程地址空间_第2张图片

【Linux进程篇】进程地址空间_第3张图片

  • 验证二(验证空间布局):

【Linux进程篇】进程地址空间_第4张图片

【Linux进程篇】进程地址空间_第5张图片

观察一个现象

在这里插入图片描述

在父子进程中分别对a进行修改,但是我们发现a的地址都为同一个,说明同一个变量在同样的地址有不同的值,如何解释?

  • 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量

  • 但地址值是一样的,说明该地址绝对不是物理地址!

  • 在Linux地址下,这种地址叫做虚拟地址

  • 我们在用C/C++语言(或者其他语言)所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理,OS必须负责将虚拟地址转化为物理地址。

进程地址空间

什么叫做地址空间?

所谓的进程地址空间,本质是一个描述进程可视范围的大小,地址空间内一定要存在各种区域划分,对线性地址进行start,和end即可,在32位计算机中,有32位的地址和数据总线,所有地址总线排列组合形成地址范围[0,232],232 * 1byte也就是4GB大小

  • cpu内存在地址寄存器(AR),保存当前CPU所访问内存单元地址
  • 虚拟地址和物理地址通过页表进行映射(页表是一种软件结构)
  • 当子进程创建时,子进程会继承父进程的虚拟地址空间,也就是说子进程和父进程指向同一块物理空间,当子进程需要对数据进行修改时,物理空间会为子进程新开辟一块空间,存储子进程修改的数据(类似于写时拷贝)

进程地址空间图示及笔记

【Linux进程篇】进程地址空间_第6张图片

从以上图可以知道,同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址。

  • 所以,什么叫进程?
    进程 = 内核数据结构(task_struct && mm_struct && 页表)+ 程序的代码和数据

所以进程在切换时task_struct && mm_struct && 页表都要进行切换

  • 进程具有独立性,怎么做到的?
  1. 内核数据结构上,进程之间是互相独立的
  2. 不同进程通过页表进行映射,将虚拟地址空间和物理地址空间进行解耦合,即便是父子进程关系只需要在页表层面上,代码区指向一样,数据区指向不一样,在数据层面上解耦合。进程若触发异常,只需要处理各自页表映射的数据即可
  • 因为有页表的存在,数据加载在物理内存的位置我们并不关心,我们只关心页表的映射关系即可。以统一的视角看待内存,让无序变有序
  • 环境变量是全局属性,因为子进程会根据父进程页表的映射关系,建立自己的页表

Linux2.6内核进程调度队列(Linxu进程篇2有涉及)

【Linux进程篇】进程概念2

如果有多个CPU就要考虑进程个数的负载均衡问题 优先级

一个CPU拥有一个runqueue(运行队列)

普通优先级:100~139(我们都是普通的优先级,想想nice值的取值范围,可与之对应!) 实时优先级:0~99(不关心)

活动队列
  • 时间片还没有结束的所有进程都按照优先级放在该队列
  • nr_active: 总共有多少个运行状态的进程
  • queue[140]: 一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以,数组下标就是优先级!
  • 从该结构中,选择一个最合适的进程,过程是怎么的呢?
  1. 从0下表开始遍历queue[140]
  2. 找到第一个非空队列,该队列必定为优先级最高的队列 3. 拿到选中队列的第一个进程,开始运行,调度完成!
  3. 遍历queue[140]时间复杂度是常数!但还是太低效了!

bitmap[5]:一共140个优先级,一共140个进程队列,为了提高查找非空队列的效率,就可以用5*32个 比特位表示队列是否为空,这样,便可以大大提高查找效率!

过期队列
  • 过期队列和活动队列结构一模一样
  • 过期队列上放置的进程,都是时间片耗尽的进程
  • 当活动队列上的进程都被处理完毕之后,对过期队列的进程进行时间片重新计算
active指针和expired指针
  • active指针永远指向活动队列
  • expired指针永远指向过期队列
  • 可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时一直都存在的。
  • 在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了一批新的活动进程!
总结
  • 在系统当中查找一个最合适调度的进程的时间复杂度是一个常数,不随着进程增多而导致时间成本增加,我们称之为进程调度O(1)算法。

你可能感兴趣的:(Linux,1024程序员节,进程地址空间,Linux)