进程地址空间

news2024/12/21 19:24:38

目录

程序地址空间

感知虚拟地址空间的存在

进程地址空间

分页 & 虚拟地址空间

Linux2.6内核进程调度队列


程序地址空间

我们在学习C语言的时候了解过程序地址空间的分布:

  •  需要注意的是:程序地址空间不是内存。我们在linux操作系统中通过代码来验证该布局。

1、🚩验证程序地址空间的分布:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int un_g_val;
int g_val=100;

int main(int argc,char*argv[],char*env[])
{
  printf("code addr            :%p\n",main);      //代码区
  printf("init global addr     :%p\n",&g_val);    //已初始化全局数据区地址
  printf("init global addr     :%p\n",&un_g_val); //未初始化全局数据区地址
  char* m1=(char*)malloc(100);
  printf("head addr            :%p\n",m1);        //堆区
  printf("stack addr           :%p\n",&m1);       //堆区
  int i=0;
  for(i=0;i<argc;i++)
  {
  printf("argv addr            :%p\n",argv[i]);
  }
  for(i=0;env[i];i++)
  {
  printf("env addr             :%p\n",env[i]);
  }
  return 0;
}

运行此程序:

  • 通过我们这段代码的运行结果来看,从上到下地址是在逐渐增大的,且栈区和堆区之间有一块非常大的地址镂空,同时这也证实了我们的程序地址空间的布局是按照上图所示的地址空间的布局。

2、🚩验证堆和栈增长方向的问题:

  • 堆:

我们用如下代码进行测试:

运行结果如下:

从运行结果来看,堆区的地址方向是向上增长的。

  •  栈:

我们用如下代码进行测试:

 从运行结果来看,栈区的地址方向是向下减少的。

总结:

  • 堆区向地址增大方向增长
  • 栈区向地址减少方向增长
  • 堆、栈相对而生。
  • 我们一般在C函数中定义的变量,通常在栈上保存,那么先定义的一定是地址比较高的(变量先定义先入栈,后定义后入栈)。

3、🚩理解static变量:

  • 我们知道对于被static修饰的变量,其作用域不变,依旧在函数内有效,但是其声明周期会随着程序一直存在,这是为什么呢?

首先我们来看一下正常定义的变量:

正常定义的变量s符合先前栈的地址分布规则:后定义的变量在地址较低处,下面我们来看一下static定义的变量:

 

  • 根据图示我们发现变量s一旦被static修饰,尽管s是在代码函数里面被定义,但此变量已经不在栈上面了,此时变成了全局变量,这也就是为什么声明周期会一直存在。

⭐结论:函数内定义的变量被static修饰,本质是编译器会把该变量编译进全局数据区内。

感知虚拟地址空间的存在

我们以下面代码为示例:

当父子进程没有人修改全局数据的时候,父子是共享该数据的!我们可以通过下面的运行结果看出:

如果我们尝试写入数据呢?

 我们看运行结果:

  • 这里我们可以看到父子进程读取的是同一个变量(地址一样),但是后续在没有人修改的情况下父子进程读取到的内容却不一样!!!明明子进程和父进程对全局变量的地址是一样的,但为什么输出的内容却不一样呢??? 

结论:我们在C/C++中使用的地址绝对不是物理地址。因为如果是物理地址,那么上述现象是绝对不会产生的!!!这种地址我们称为虚拟地址、线性地址、逻辑地址

🤔为什么操作系统不让我们直接看到物理内存呢??

  • 因为这并不安全,内存是一个硬件,不能够阻拦你访问!只有被动的进行读取和写入。所以为了防止系统故障的发生,我们不能够直接访问。

进程地址空间

其实我们之前说"程序的地址空间"是不准确的,准确的说应该是进程地址空间

  • 每一个进程在启动的时候,都会让操作系统给它创建一个地址空间,该地址空间就是进程地址空间。每一个进程都会有一个自己的进程地址空间。操作系统需要管理这些进程地址空间,依旧是先描述,再组织。所谓的进程地址空间,其实是内核的一个数据结构(struct mm_struct )

  • 在前面我们提到过进程是具有独立性的,体现在相关的数据结构是独立的,进程的代码和数据是独立的等等......这其实是操作系统给每个进程画的大饼,让每一个进程都认为自己是独占系统中的所有资源的!!!事实是所谓的地址空间其实就是OS通过软件的方式,给进程提供一个软件视角,认为自己会独占系统的所有资源(内存)。

分页 & 虚拟地址空间

在Linux内核中,每个进程都有task_struct结构体,该结构体有个指针指向一个结构mm_struct(程序地址空间),我们假设磁盘的一个程序被加载到物理内存,我们需要将虚拟地址空间和物理内存之间建立映射关系,这种映射关系是通过页表(映射表)的结构来完成的(操作系统会给每一个进程构建一个页表结构)。如下图:

🚩问: 区域是如何划分的?

  • mm_struct划分的机制就是和上图一样,此结构体就是按照类似如下的代码方式进行限制的:
struct mm_struct
{
    long code_start;
    long code_end;
 
    long init_start;
    long init_end;
    
    long uninit_start;
    long uninit_end;
    //……
}

🚩问: 程序是如何变成进程的?

  • 程序被编译出来,没有被加载的时候,程序内部是有地址和区域的。不过这里的地址采用的是相对地址的方式,而区域实际是在磁盘上已经划分好了。加载无非就是按照区域加载到内存。

🚩问:为什么先前修改一个进程时,地址是一样的,但是父子进程访问的内容却是不一样的?

  • 父子进程创建都有其各自专属的task_struct和地址空间mm_struct,虚拟地址空间通过页表映射到物理内存:

  • 当子进程刚刚创建的时候,子进程和父进程的数据和代码是共享的,即父子进程的代码和数据通过页表映射到物理内存的同一块空间。所以我们先前打印的g_val的值和内容全部一样。而当子进程修改完g_val的数据后,结果就发生了变化。

  •  因为操作系统要做到使进程具有独立性,如果子进程把变量g_val修改了,那么就会导致父进程识别此变量的时候出现问题,但是独立性的要求是互不影响,所以此时操作系统会给子进程重新开辟一块内存空间。把先前g_val的值100拷贝下来,重新给此进程建立映射关系,所以子进程的页表就不再指向父进程的数据100了,而是指向新的100,此时把100修改为200,无论怎么修改,变动的永远都是右侧,左侧页表间的关系不变,所以最终读到的结果为子进程是200,父进程是100。但其虚拟地址空间值还一样,所以这也就解释了我们前面出现的现象。
  • 结论:当父子进程对数据修改的时候,操作系统会给修改的一方在物理内存中重新开辟一块空间,并且把原始数据拷贝到新空间中,这种行为我们称之为写时拷贝。通过页表,将父子进程的数据就可以通过写时拷贝的方式,进行了分离。从而做到父子进程具有独立性的特点。

🚩问:为什么fork有两个返回值,即对于变量pid_t  id怎么有不同的值?

  • 一般情况下,pid_t id是属于父进程的栈空间中定义的变量,fork内部,return会被执行两次,return的本质就是通过寄存器将返回值写入到接收返回值的变量中!当id = fork()的时候,谁先返回,谁就要发生写时拷贝,所以,同一个变量,会有不同的内容值,本质是因为大家的虚拟地址是一样的,但是大家对应的物理地址是不一样的。

🚩问:为什么要有虚拟地址空间?

  • 保护内存。假设我们写了个非法访问野指针(*p = 111),假设此野指针指向了进程2,甚至直接指向了操作系统,那么当你进行访问的时候,你就会直接修改其它进程的数据,所以直接让进程访问物理内存的方式是不安全的。如果我们假设虚拟地址空间就不会出现这种现象了,因为遇到野指针,页表就不会给你建立映射关系,那么就不会给你访问到物理内存的机会。综上,有了虚拟地址空间,相当于在访问内存的时候添加了一层软硬件层,可以对转化过程进行审核,非法的请求就可以直接拦截了。
  • 可以把Linux内存管理,进程管理通过地址空间进行功能模块的解耦。
  • 让进程或者程序可以以一种统一的视角看待内存,方便以统一的方式来编译和加载所有的可执行程序,简化进程本身的设计与实现!

Linux2.6内核进程调度队列

⭐:一个CPU拥有一个runqueue 

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

⭐:优先级

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

⭐:活动队列

  • 时间片还没有结束的所有进程都按照优先级放在该队列。
  • nr_active: 总共有多少个运行状态的进程。
  • queue[140]: 一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以,数组下标就是优先级!

从该结构中,选择一个最合适的进程,过程是怎么的呢?🤔

  1. 从0下表开始遍历queue[140]。
  2. 找到第一个非空队列,该队列必定为优先级最高的队列。
  3. 拿到选中队列的第一个进程,开始运行,调度完成!
  4. 遍历queue[140]时间复杂度是常数!但还是太低效了!

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

⭐:过期队列

  • 过期队列和活动队列结构一模一样。
  • 过期队列上放置的进程,都是时间片耗尽的进程。
  • 当活动队列上的进程都被处理完毕之后,对过期队列的进程进行时间片重新计算。

⭐:active指针和expired指针

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

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

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

相关文章

刷题笔记之二(字符串中找出连续最长的数字串+数组中出现次数超过一半的数字+另类加法+计算糖果+进制转换)

目录 1. 多层继承问题 2. 继承中子类的构造要引用super 3. 比较地址 4. 字符串中找出连续最长的数字串(编程题) 5. 数组中出现次数超过一半的数字&#xff08;编程题&#xff09; 6. 另类加法&#xff08;编程题&#xff09; 7. Interface 接口中定义方法 8. 实现或继…

C语言学习(二)之字符串和格式化输入/输出

文章目录一、字符串二、 输入2.1 scanf()作用2.2 两种用法三、输出3.1 printf()3.1.1 printf 四种用法3.1.2 常用输出控制符3.1.3 为什么需要输出控制符一、字符串 字符串是一个或多个字符的序列。如&#xff1a;“Hello World” 双引号不是字符串的一部分。仅告知编译器它括…

【学习笔记】《深入浅出Pandas》第16章:可视化

文章目录16.1 plot方法16.1.1 plot概述16.1.2 plot基础方法16.1.3 图形类型16.1.4 x轴和y轴16.1.5 图形标题16.1.6 字体大小16.1.7 线条样式16.1.8 背景辅助线16.1.9 图例16.1.10 图形大小16.1.11 色系16.1.12 绘图引擎16.1.14 图形叠加16.1.15 颜色的表示16.1.16 解决图形中的…

量子笔记:量子计算 toy python implementation from scratch

目录 0. 概要 1. 量子比特表示&#xff1a;用二维张量表示 2. 张量积的实现 2.1 用scipy.linalg.kron()实现张量积 2.2 用张量积计算双量子系统的基 3. 多量子系统基向量表示和生成 3.1 Helper function: bin_ext 3.2 多量子系统的基的生成 3.3 numpy.matrix numpy.m…

基于多尺度注意力网络单图像超分(MAN)

引言 Transformer的自注意力机制可以进行远距离建模&#xff0c;在视觉的各个领域表现出强大的能力。然而在VAN中使用大核分解同样可以得到很好的效果。这也反映了卷积核的发展趋势&#xff0c;从一开始的大卷积核到vgg中采用堆叠的小卷积核代替大卷积核。 上图展现了MAN网络在…

使用T0,方式2,在P1.0输出周期为400µs,占空比为4:1的矩形脉冲,要求在P1.0引脚接有虚拟示波器,观察P1.0引脚输出的矩形脉冲波形

大家学过一段时间的单片机了&#xff0c;今天我们来说说单片机里的定时器&#xff0c;又叫计数器。首先&#xff0c;我们通过案例来了解一下什么是定时器。 【例】使用T0&#xff0c;方式2&#xff0c;在P1.0输出周期为400s&#xff0c;占空比为4&#xff1a;1的矩形脉冲&…

如何编写优秀的测试用例,建议收藏和转发

1、测试点与测试用例 测试点不等于测试用例&#xff0c;这是我们首先需要认识到的。 问题1&#xff1a;这些测试点在内容上有重复&#xff0c;存在冗余。 问题2&#xff1a;一些测试点的测试输入不明确&#xff0c;不知道测试时要测试哪些。 问题3&#xff1a;总是在搭相似…

串口通信协议【I2C、SPI、UART、RS232、RS485、CAN】

&#xff08;1&#xff09;I2C 集成电路互连总线接口(Inter IC)&#xff1a;同步串行半双工传输总线&#xff0c;连接嵌入式处理器及其外围器件。 支持器件&#xff1a;LCD驱动器、Flash存储器 特点&#xff1a; ①有两根传输线&#xff08;时钟线SCL、双向数据线SDA&#…

python基础19-36题

题目&#xff1a; 代码十九二十二十一二十二二十三二十四二十五二十六二十七二十八二十九三十三十一三十二三十三三十四三十五三十六十九 birthday int(input(“请输入生日日期&#xff1a;”)) Set1 [1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31] Set2 [2,3,6,7,10,11,…

【CV】第 7 章:目标检测基础

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

几何等变图神经网络综述

许多科学问题都要求以几何图形&#xff08;geometric graphs&#xff09;的形式处理数据。与一般图数据不同&#xff0c;几何图显示平移、旋转和反射的对称性。研究人员利用这种对称性的归纳偏差&#xff08;inductive bias&#xff09;&#xff0c;开发了几何等变图神经网络&a…

SpringMVC | 快速上手SpringMVC

&#x1f451; 博主简介&#xff1a;    &#x1f947; Java领域新星创作者    &#x1f947; 阿里云开发者社区专家博主、星级博主、技术博主 &#x1f91d; 交流社区&#xff1a;BoBooY&#xff08;优质编程学习笔记社区&#xff09; 前言&#xff1a;在上一节中我们了解…

多分类评估指标计算

文章目录混淆矩阵回顾Precision、Recall、F1回顾多分类混淆矩阵宏平均&#xff08;Macro-average&#xff09;微平均&#xff08;Micro-average&#xff09;加权平均&#xff08;Weighted-average&#xff09;总结代码混淆矩阵回顾 若一个实例是正类&#xff0c;并且被预测为正…

Linux(Nginx)

目录 一、Nginx简介 二、Nginx使用 Nginx安装 tomcat负载均衡 Nginx配置 三、Nginx部署项目 项目打包前 将前端项目打包&#xff08;测试本地项目打包后没问题&#xff09; ip/host主机映射 完成Nginx动静分离的default.conf的相关配置 将前台项目打包(配合Nginx动静…

real-word super resulution: real-sr, real-vsr, realbasicvsr 三篇超分和视频超分论文

real-world image and video super-resolution 文章目录real-world image and video super-resolution1. Toward Real-World Single Image Super-Resolution:A New Benchmark and A New Model&#xff08;2019&#xff09;1.1 real-world数据集制作1.2 LP-KPN网络结构1.3 拉普拉…

近八成中国程序员起薪过万人民币,你过了么?

打工者联盟为了抵抗996、拖欠工资、黑心老板、恶心公司&#xff0c;让我们组成打工者联盟。客观评价自己任职过的公司情况&#xff0c;为其他求职者竖起一座引路的明灯。https://book.employleague.cn/一项调查显示&#xff0c;近八成中国程序员本科毕业生起薪过万&#xff08;…

Oracle数据库中的数据完整性

目录 1.数据完整性约束作用 2.数据完整性约束的分类 3.完整性约束的状态 4.域完整性的实现 &#xff08;1&#xff09;check约束 ①可视化方式创建check约束 ②命令方式创建约束 ③修改表创建的约束 ④删除约束 &#xff08;2&#xff09;实体完整性约束实现 ①prim…

思科dhcp服务器动态获取ip地址

项目要求: 某公司共有网管中心、行政部、技术部、三个部门&#xff0c;分别处在一栋大楼中的两个楼层&#xff0c;为了保证公司内部主机始终能够连接Internet&#xff0c;采用双向冗余设计&#xff0c;分别使用路由器R1与路由器R2连接中国电信和中国联通。 1.首先为了避免不必要…

【算法详解】数据结构:7种哈希散列算法,你知道几个?

一、前言 哈希表的历史 哈希散列的想法在不同的地方独立出现。1953 年 1 月&#xff0c;汉斯彼得卢恩 ( Hans Peter Luhn ) 编写了一份IBM内部备忘录&#xff0c;其中使用了散列和链接。开放寻址后来由 AD Linh 在 Luhn 的论文上提出。大约在同一时间&#xff0c;IBM Researc…

项目进度管理

第3 章 项目进度管理 3.1 概述 1.项目进度管理是指在项目实施过程中&#xff0c;对各阶段的进展程度和项目最终完成的期限所进行的管理&#xff0c;是在 规定的时间内&#xff0c;拟定出合理且经济的进度计划&#xff08;包括多级管理的子汁划)&#xff0c;在执行该计划的过程…