【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.mzph.cn/news/769344.shtml

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

相关文章

vue2 和 vue3 配置路由有什么区别

vue2 和 vue3 配置路由有什么区别 初始化路由器实例&#xff1a;注入到应用中&#xff1a;动态路由参数和捕获所有路由&#xff1a;编程式导航 API&#xff1a;异步加载组件&#xff1a; vue2 如何 使用路由 第一步&#xff1a;安装 vue-router第二步&#xff1a;创建路由组件第…

【k8s】kubeasz 3.6.3 + virtualbox 搭建本地虚拟机openeuler 22.03 三节点集群 离线方案

kubeasz项目源码地址 GitHub - easzlab/kubeasz: 使用Ansible脚本安装K8S集群&#xff0c;介绍组件交互原理&#xff0c;方便直接&#xff0c;不受国内网络环境影响 拉取代码&#xff0c;并切换到最近发布的分支 git clone https://github.com/easzlab/kubeasz cd kubeasz gi…

<Linux> 模拟实现文件流 - 简易版

目录 1. FILE 结构设计 2、函数使用及分析 3、文件打开 fopen 4. 缓冲区刷新fflush 5. 数据写入fwrite 6. 文件关闭 fclose 7. 测试 8. 小结 1. FILE 结构设计 在设计 FILE 结构体前&#xff0c;首先要清楚 FILE 中有自己的缓冲区及冲刷方式 缓冲区的大小和刷新方式因…

JVM监控工具

JVM监控工具 文章目录 JVM监控工具jpsjmapjmap -histo 进程idjmap -heap 进程id (查看堆信息)jmap -dump:formatb,filefilename.hprof 进程id (将堆当前时刻快照信息dump到文件中) JSTACKjstack 查看死锁信息jstack找出占用cpu最高的线程堆栈信息 jinfo查看jvm参数查看java系统…

Perfetto Trace抓取

1. Perfetto简介 Perfetto 是一个用于 Android 系统的性能跟踪工具&#xff0c;可以帮助开发者分析系统性能和调试问题。 Perfetto 是 Android 10 中引入的全新平台级跟踪工具。这是适用于 Android、Linux 和 Chrome 的更加通用和复杂的开源跟踪项目。 在低于Android R的版本上…

量子计算新“尺度”:用经典计算机评估复杂量子系统!

未来的量子计算机有望在计算机科学、医疗、商业、化学、物理学等多个领域解决难题&#xff0c;从而超越传统计算机。然而&#xff0c;目前的量子计算机仍存在局限&#xff0c;主要是由于它们固有的错误率。为此&#xff0c;研究者正致力于降低这些错误率。 一种研究量子计算机误…

Linux系统部署Paperless-Ngx文档管理系统结合内网穿透实现公网访问

文章目录 1. 部署Paperless-ngx2. 本地访问Paperless-ngx3. Linux安装Cpolar4. 配置公网地址5. 远程访问6. 固定Cpolar公网地址7. 固定地址访问 Paperless-ngx是一个开源的文档管理系统&#xff0c;可以将物理文档转换成可搜索的在线档案&#xff0c;从而减少纸张的使用。它内置…

机械硬盘与固态硬盘究竟该适合选用哪种,看完本文你就了解了!

随着科技的发展,计算机存储技术经历了从传统的机械硬盘(HDD)到现代固态硬盘(SSD)的革新变迁。在这篇文章中,我们将深入探讨机械硬盘与固态硬盘在功能特点上的显著区别,帮助用户更好地理解这两种存储设备的核心优势与不足。 一、存储原理与结构差异 1. 机械硬盘(HDD) …

Midjourney AI绘图工具介绍及使用

介绍 Midjourney是一款目前被誉为最强的AI绘图工具。只要输入想到的文字&#xff0c;就能通过人工智能产出相对应的图片。 官网只是宣传和登录入口&#xff0c;提供个人主页、订阅管理等功能&#xff0c;Midjourney实际的绘画功能&#xff0c;是在另外一个叫discord的产品中实…

网络电视盒子哪个品牌好?2024畅销电视盒子排行榜

电视盒子的品牌和产品非常多&#xff0c;让新手在选购时难度增大&#xff0c;大部分消费者在此时会选择参考销量排名情况&#xff0c;小编这次结合各个电商平台的销量和用户评价整理了电视盒子排行榜&#xff0c;想买电视盒子不知道网络电视盒子哪个品牌好可以收藏。 TOP 1.泰捷…

论文导读 | 漫谈图神经网络

本文主要介绍图神经网络相关内容&#xff0c;包括图神经网络的基本结构以及近期研究进展。 背景 在实际生活中&#xff0c;许多数据都可以用图的形式表达&#xff0c;比如社交网络、分子模型、知识图谱、计算机网络等。图深度学习旨在&#xff0c;显式利用这些数据中的拓扑结…

3.18_C++_day6_作业

作业要求&#xff1a; 程序代码&#xff1a; #include <iostream>using namespace std;class Animal { private:string name;string color;int *age; public://无参构造函数Animal(){cout << "Animal::无参构造函数" << endl;}//有参构造函数Anim…

[Linux初阶]which-find-grep-wc-管道符命令

目录 一.which 二.find a.-name b.-size 三.grep 四.wc 五.管道符(|) 五.总结 一.which 语法格式: which [命令] Linux中的一个个命令,本体上就是一个个的二进制可执行程序(相当于windows中的.exe文件). 在Linux中,一切皆文件. which命令:用于查看指定命令的可执行…

【JS进阶】第3天

JavaScript 进阶 - 第3天笔记 理论较多&#xff0c;主要讲解原型对象和对象原型 了解构造函数原型对象的语法特征&#xff0c;掌握 JavaScript 中面向对象编程的实现方式&#xff0c;基于面向对象编程思想实现 DOM 操作的封装。 了解面向对象编程的一般特征掌握基于构造函数原…

饼图渲染的关键

1) 创建一个DOM对象,有自定义的高和宽. 2) 引入Echarts软件包并导入到对应文件内 npm i Echarts import 文件.js script src.../文件 3) 初始化一个对象 4) 对象的方法实现饼图渲染 data内的数据,且当一个对象已经渲染一遍,再执行这个,会对setOption的参数进行更新,其…

Adobe Illustrator和Photoshop哪个难学?另一款好用设计软件上位!

当设计开始时&#xff0c;几乎没有人不知道。 Adobe 公司的两大设计软件&#xff1a;Adobe Illustrator 和 Photoshop。虽然 Adobe Illustrator和 Photoshop 很有名&#xff0c;有一定设计经验的设计师在前期探索使用后可以对 Adobe Illustrator和 Photoshop 的使用差异有一个大…

NEC 78K系列MCU概述

一.初识 NEC MCU NEC&#xff0c;即日本电气株式会社&#xff0c; 经营半导体业务。 NEC 倡导“ ALL Flash”&#xff0c;即 MCU 内的程序存储器使用 Flash ROM。 为什么用 Flash ROM&#xff1f; 与掩膜 ROM 微控制器相比&#xff0c; Flash 微控制器加速了系…

理解java进程和多线程

一、进程是什么&#xff0c;线程是什么&#xff1f; (1)理解&#xff1a; 进程是一个主体任务&#xff0c;线程是这个进程下的子任务&#xff0c;下图解释&#xff1a; 描述&#xff1a;一个餐厅好比一个进程&#xff0c;一个餐厅下面有多个职位的厨师&#xff0c;他们分别是…

Java代码基础算法练习-公式求和-2024.03.24

任务描述&#xff1a; 求公式Snaaaaaa…aa…aaa&#xff08;有n个a&#xff09;之值&#xff0c;其中a是一个数字&#xff0c;为2。 例如&#xff0c;n5 时222222222222222&#xff0c;n 由键盘输入(n<5)。 任务要求&#xff1a; package march0317_0331;import java.util.…

React函数组件Hook

问题: 相对于类组件, 函数组件的编码更简单, 效率也更高, 但函数组件不能有state (旧版) 解决: React 16.8版本设计了一套新的语法来让函数组件也可以有state Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性 Hook也叫钩子…