【linux】进程的地址空间

1.代码看现象引入

 #include<stdio.h>#include<unistd.h>#include<string.h>   #include<stdlib.h>int val=100;int main (){ printf("i am father,pid:%d,ppid:%d,val:%d,&val:%p\n",getpid(),getppid(),val,&val);size_t id=fork();if(id==0){int cnt=0;while(1){printf("i am child,pid:%d,ppid:%d,val:%d,&val:%p\n",getpid(),getppid(),val,&val);cnt++;sleep(1);if(cnt==5)                                                                                                    {val=300;}}}else {  while(1){ printf("i am father,pid:%d,ppid:%d,val:%d,&val:%p\n",getpid(),getppid(),val,&val);sleep(1);}}  } 

代码解释:定义一个全局变量,然后创建子进程,让子进程在5秒开始修改这个值,观察子进程和父进程这个全局变量是否一样
在这里插入图片描述

我们发现val变量子进程和父进程的值不一样,这个我们可以理解,因为进程的独立性,导致父进程和子进程的val不一样,但是为什么val两个的地址还是一样的

解释:这里的地址并非物理地址,同一个物理地址只可能出现一个值,这里的地址其实是进程的地址空间,也叫做虚拟地址。

2.虚拟空间的理解

当我们有进程执行的时候,会将代码和数据从磁盘加载到物理内存中去,操作系统会对这个进程创建一个进程task_struct来描述这个进程,而这个对应进程的pcb中存在的是这个进程的地址空间的地址,这里的地址空间就是我们之前学过的包括命令行参数和环境变量的虚拟地址,栈的虚拟地址,堆的虚拟地址,以及初始化数据的虚拟地址,以及正文代码的虚拟地址,而这些虚拟地址怎么找到该变量的实际地址也就是物理地址呢??这里就要提到一个叫页表的东西,页表将变量的虚拟地址和物理内存的实际地址对应上了,下面画图带大家理解一下
在这里插入图片描述
而对于地址空间,到底是什么东西呢??要想理解这个地址空间,我们可以先来理解一下什么是划分区域。
当我们有一个长100cm的桌子,你和你·同桌要划分三八线,你两一人50cm,然后过了几天,然后你和你同桌商量将你的地盘多加20,然后你就有70cm长,然后他只有30cm,实现了区域的调整。
那如何通过计算机语言来实现呢?
我们可以先定义一个结构体,来确定一个人的边界

struct area
{
int start;
int end;}
struct area destop
{struct area left;struct area right;
}
struct area destop res;
res.left.start=0;
res.left.end=50;
res.right.start=50;
res.right.start=100;
//如果要变化
res.left.end+=20;
res.right.start-=20;

实际上地址空间本质就是一个结构体对象,里面存了好多虚拟地址的范围,给大家看一下linux里面的地址空间的结构

struct mm_struct
{unsigned long start_code; // 代码段的开始地址unsigned long end_code; // 代码段的结束地址unsigned long start_data; // 数据的首地址unsigned long end_data; // 数据的尾地址unsigned long start_brk; // 堆的首地址unsigned long brk; // 堆的尾地址unsigned long start_stack; // 进程栈的首地址//...
};

假如我要在堆区申请空间,由于堆是向上生长,所以他申请的空间时,会让start_brk–
腾出要申请空间的大小

地址空间上的虚拟地址和页表上的地址信息是从哪里来的呢??
实际上页表上的地址和地址空间的地址来自于程序
我们可以通过下面的指令查看反汇编

 objdump -S 可执行程序的名称

在这里插入图片描述

3.接着利用现有的虚拟空间的理解来解释上面的代码父子进程全局变量的虚拟地址为啥相同

父进程创建子进程时,会继承父进程的基本所有数据,当然不包括pid,ppid以及其他的.比方说拷贝父进程地地址空间,以及父进程的页表,下面画图来理解一下

在这里插入图片描述

这种拷贝在c++中我们学过叫浅拷贝,我们之前为了防止这种浅拷贝在析构的时候析构多次出现错误,我们引入了一个概念叫引用计数,当计数值大于1时说明该空间被多个虚拟地址共享,我们当引用计数为1时在析构,就解决了了当时的问题,而子进程要进行修改这个变量的时候,操作系统就会使用写时拷贝,给子进程的val在创建一个物理空间,该物理空间里的val值就是子进程修改之后的val,而子进程和父进程的val的虚拟地址一样,但是物理地址不一样,发生了写时拷贝,只有在子进程要修改的时候才进行写时拷贝,通过调整拷贝的时间顺序,达到有效节省空间的目的
在这里插入图片描述

#include<stdio.h>#include<unistd.h>#include<string.h>   #include<stdlib.h>int main(){size_t id=fork();if(id==0){printf("i am child  id:%d,&id:%p\n",id,&id);}else{printf("i am father  id:%d,&id:%p\n",id,&id);}}

在这里插入图片描述

这里我们就懂这段代码了吧

4.为什么要有地址空间

原因1在这里插入图片描述
根据图我们可以知道进程1的变量会随机的散落在物理内存中,如果我们将同一类型的变量划分在同一个区域里面会显得特别规整,所以我们引入了地址空间,让无序变成有序,让进程以统一的视角看待物理内存以及自己运行的区域

原因2
当我们实际的某一块物理内存中没有数据,我们在页表里面访问虚拟地址没有对应的物理内存,就会进行拦截非法请求,对物理内存进行保护。
原因3
进程管理模块和内存管理模块进行解耦


5.进一步理解页表和写时拷贝

CR3寄存器:
在这里插入图片描述

MMU是一种硬件设备,也称为内存管理单元,它位于计算机系统的中央处理器(CPU)和内存之间。MMU负责处理程序发出的内存访问请求,并将逻辑地址转换为物理地址,实现对内存的管理和保护

这里会让CR3寄存器保存对应进程的页表的起始地址,然后MMU会将地址空间里面的虚拟地址转化为物理地址,填到相应页表中,实现了地址的对应关系


页表不单单只是存虚拟空间和物理空间的地址
在这里插入图片描述

当运行一个进程时,会将他的代码和数据加载进物理内存,我们在上篇文章中提到过,如果内存不足的时候,操作系统会将
长时间不执行的进程的代码和数据挂起,将代码和数据移动到硬盘的swap区,此时在对应页表的是否存在于内存中就可以标记为0。

#include<iostream>
using namespace std;
int main()
{const char* ptr = "hello world"; *ptr="hello";printf("%s", ptr);}

针对上面的代码为什么不行,因为*ptr是在常量区的,对应页表里面的wrx权限里面是没有写权限的,所以不能被修改。

然后我们再次理解第三个问题时,子进程和父进程
当子进程拷贝了父进程的地址空间和页表时,然后val值对应的页表那一栏,wrx权限修改成r(只读)
当子进程要修改时
操作系统会做一下判断,操作系统识别到错误
1.是不是在物理内存里(发生缺页中断)
2.是不是数据需要写时拷贝(发生写时拷贝)
3.如果不是才进行异常处理

6.linux是如何调度的?

我们之前讲优先级默认值为80,然后Nice可以调整优先级,Nice的范围是-20到19
也就说明优先级是60-99的,就是40个优先级
在这里插入图片描述

在这里插入图片描述

queue是一个指针数组,每一个指针数组里面存放的是对应优先级的进程pcb结构的地址,前100个不用,后面40个正好对应40个优先级,当运行一个进程时,就将这个进程的pcb结构连接在对应优先级的后面,之前说过各个pcb结构是通过双向链表连接起来。前面的pcb结构存放了后面pcb结构的地址,如果要找出哪个优先级对应的指针数组有pcb结构,难道要挨着遍历吗,这里有一个 long bitmap[5]数组
long 是四个字节,一个可以存放32个比特位,32*5=160

bitmap[0]:00000000 00000000 00000000 00000000  //前32个不用
bitmap[1]:00000000 00000000 00000000 00000000  //前64个不用
bitmap[2]:00000000 00000000 00000000 00000000  //前96个不用
bitmap[3]:0000 //前100个不用  0000 00000000 00000000 00000000  
bitmap[4]:00000000 00000000 00000000 00000000

然后剩下的40个如果对应优先级上有进程的pcb结构话,就置1,没有就置0,


上面还有一个活跃进程和一个过期进程array[0],array[1]
活跃进程只出不进,过期进程只进不出。
活跃进程里面的进程pcb,如果代码片到了的话,就会将对应的pcb结构放到过期进程中去,如果进程被挂起,也会放到过期进程里面去,然后活跃进程完成他里面的所有进程后,就会交换array[0],array[1]的地址也就是过期进程变成了活跃进程,活跃进程变成了过期进程,而新的进程被加载到内存,是被放到就绪队列中去,我感觉活跃队列是正在运行的队列,而另一个过期队列就是就绪队列,他好像要交换一下,过期队列就成了活跃队列,也就是运行队列。

swap(&array[0],&array[1]);

改变后的指针指向在这里插入图片描述

本来是

*active=&array[0];
*expired=&array[1];

改变后是

*active=&array[1];
*expired=&array[0];

我们就可以通过O(1)的时间复杂度来确定哪个优先级上有pcb结构


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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux:点命令source

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 source命令用于读取一个文件的内容并在当前Shell环境&#xff08;包括交互式Shell或是非交互式Shell&#xff09;执行里面的命令。它被称为点命令是因为命令名source也可…

IIS7/iis8/iis10安装II6兼容模块 以windows2022为例

因安全狗的提示 安全狗防护引|擎安装失败 可能原因是: IIS7及以上版本末安装1IS6兼容模块! .所以操作解决 如下. 在开始菜单中,找到服务器管理器.找到下图的IIS,右键添加角色和功能,找到web服务器的管理工具选项,iis6管理兼容性 打钩并安装. 如下图

自然拼读-组合音(上篇)

自然拼读-组合音 1、元音字母A的二声发音组合 组合音at 注意&#xff1a;“t”是气音&#xff0c;不要太重。 Eg&#xff1a;cat&#xff08;猫&#xff09; fat&#xff08;肥的&#xff09; bat&#xff08;蝙蝠&#xff09; 组合音ap 注意&#xff1a;“p”在尾巴发音…

MRC是谁?- 媒体评级委员会 Media Rating Council

在在线广告的世界里&#xff0c;有许多不同的技术和实践用于提供和衡量广告。对于广告商、出版商和营销人员来说&#xff0c;了解这些技术是如何工作的以及如何有效使用这些技术很重要。在这方面发挥关键作用的一个组织是媒体评级委员会&#xff08;MRC&#xff09;。 1. 了解…

蓝桥杯基础练习详细讲解二(具体代码、解题思路、Python)

试题 基础练习 回文数 提交此题 评测记录 资源限制 内存限制&#xff1a;512.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 1221是一个非常特殊的数&#xff0c;它从左边读和从右边读是一样的&#x…

mysql基础3索引

存储引擎 存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式 。存储引擎是基于表的&#xff0c;而不是 基于库的&#xff0c;所以存储引擎也可被称为表类型。 1). 建表时指定存储引擎 CREATE TABLE 表名(字段1 字段1类型 [ COMMENT 字段1注释 ] ,......字段n…

Docker进阶:Docker-compose 实现服务弹性伸缩

Docker进阶&#xff1a;Docker-compose 实现服务弹性伸缩 一、Docker Compose基础概念1.1 Docker Compose简介1.2 Docker Compose文件结构 二、弹性伸缩的原理和实现步骤2.1 弹性伸缩原理2.2 实现步骤 三、技术实践案例3.1 场景描述3.2 配置Docker Compose文件3.3 使用 docker-…

【项目管理后台】Vue3+Ts+Sass实战框架搭建二

Vue3TsSass搭建 git cz的配置mock 数据配置viteMockServe 建立mock/user.ts文件夹测试一下mock是否配置成功 axios二次封装解决env报错问题&#xff0c;ImportMeta”上不存在属性“env” 统一管理相关接口新建api/index.js 路由的配置建立router/index.ts将路由进行集中封装&am…

AIGC实战——Transformer模型

AIGC实战——Transformer模型 0. 前言1. T52. GPT-3 和 GPT-43. ChatGPT小结系列链接 0. 前言 我们在 GPT (Generative Pre-trained Transformer) 一节所构建的 GPT 模型是一个解码器 Transformer&#xff0c;它逐字符地生成文本字符串&#xff0c;并使用因果掩码只关注输入字…

海外媒体宣发:十大国外中文网站-大舍传媒

十大国外中文网站 1、欧洲时报 覆盖欧洲且较具影响力的华文媒体 国外中文新闻网站&#xff0c;欧洲时报文化传媒集团旗舰日报《欧洲时报》旗下官方网站&#xff0c;总部设在法国巴黎&#xff0c;创刊于1983年&#xff0c;现已成为唯一发行覆盖全欧、发行量最大、最具影响力的华…

Vue3 上手笔记

1. Vue3简介 2020年9月18日&#xff0c;Vue.js发布版3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;n 经历了&#xff1a;4800次提交、40个RFC、600次PR、300贡献者 官方发版地址&#xff1a;Release v3.0.0 One Piece vuejs/core 截止2023年10月&#xff0c;最…

STM32最小核心板使用HAL库ADC读取MCU温度(使用DMA通道)

STM32自带CPU的温度数据&#xff0c;需要使用ADC去读取。因此在MX创建项目时如图配置&#xff1a; 模块初始化代码如下&#xff1a; void MX_ADC1_Init(void) {/* USER CODE BEGIN ADC1_Init 0 *//* USER CODE END ADC1_Init 0 */ADC_ChannelConfTypeDef sConfig {0};/* USER…

Docker 入门使用说明

Docker 入门使用说明 Docker 安装 Docker 官网&#xff1a;Docker Docker 安装说明&#xff1a;Docker 安装说明 这里由于 Docker 在实时更新&#xff0c;所以每次安装 Docker 用来导入 key 的链接可能会有变化&#xff0c;这里就参考官方的安装方法即可 Docker 常用命令说…

(ES6)前端八股文修炼Day2

1. let const var 的区别 var&#xff1a; var 是在 ES5 中引入的声明变量的关键字。 具有函数作用域&#xff0c;而不是块作用域&#xff0c;这意味着使用 var 声明的变量在函数内部是可见的。 变量可以被重复声明&#xff0c;而且变量的值可以在声明前使用&#xff0c;这可能…

生成微信小程序二维码

首页 -> 统计 可以通过上面二个地方配置&#xff0c;生成小程序的二维码&#xff0c;并且在推广分析里&#xff0c;有详细的分析数据&#xff0c;

Vue3更新Package.json版本号

由于我之前已经更新过了&#xff0c;下面的方法提示我已经是最新的了&#xff0c;记录一下&#xff0c;过段时间在测试一下 npm install -g vue/clivue upgrade

【Hadoop大数据技术】——Hadoop高可用集群(学习笔记)

&#x1f4d6; 前言&#xff1a;Hadoop设计之初&#xff0c;在架构设计和应用性能方面存在很多不如人意的地方&#xff0c;如HDFS和YARN集群的主节点只能有一个&#xff0c;如果主节点宕机无法使用&#xff0c;那么将导致HDFS或YARN集群无法使用&#xff0c;针对上述问题&#…

项目1-加法计算器

1.创建项目 2.导入前端代码 2.1 static包内 2.2 测试前端代码是否有误 显示成功说明无误 2.3 定义用户接口 请求路径&#xff1a;calc/sum 请求方式&#xff1a;GET/POST 接口描述&#xff1a;计算两个整数相加 请求参数: 参数名类型是否必须备注num1Integer是参与计算的第…

YiYi-Web项目介绍

YiYi-Web项目介绍 1. 简介2. 使用2.1 后端开发环境2.2 前端开发环境 3. 测试环境&#xff1a;4. 更新日志5. 打包情况6.项目截图 本项目前端是html、css、js、jQuery基础技术。 后端都是最新的SpringBoot技术&#xff0c;不分离版本&#xff0c; 是最基础的项目开发教程&#x…

【C语言】linux内核pci_alloc_irq_vectors

一、注释 代码中包含了几个关于PCI&#xff08;外围组件互联&#xff09;设备中断请求&#xff08;IRQ&#xff09;向量分配的函数&#xff0c;以及内联函数声明&#xff0c;下面是对这些函数的中文注释&#xff1a; static inline int pci_alloc_irq_vectors_affinity(struc…