【linux】进程的地址空间

news2024/9/22 15:35:24

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.coloradmin.cn/o/1543353.html

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

相关文章

Spring中@Service 、@Component、@Repository等注解区别是什么?

一、问题解析 在Spring框架中&#xff0c;有很多用来声明Spring管理的bean的常用注解。它们都是Component的特化形式&#xff0c;用于指定不同类型的组件&#xff0c;主要有以下几个&#xff1a; 1Component&#xff1a;是一个通用的组件声明注解&#xff0c;表示该类是一个Sp…

利用PSR,三步实现业务快速加载

01 什么是PSR PSR是通信业界在BSS/OSS域面向产品设计和业务开通过程中提出的一个标准化信息分层解耦和映射的框架&#xff0c;按照国际电信论坛TMF推荐的SID信息框架的标准&#xff0c;主要分为产品域、服务域和资源域等三层&#xff0c;支撑通信业务的快速加载和敏捷开通。 TM…

【LeetCode: 4. 寻找两个正序数组的中位数 + 二分查找】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

海外客户获取难?海外云手机助力电商引流!

海外电商面临的市场竞争激烈&#xff0c;如何在海外市场获客成为了摆在许多卖家面前的难题。而在这个问题的解决方案中&#xff0c;海外云手机崭露头角&#xff0c;成为助力电商引流的新利器。 在当前市场中&#xff0c;云手机主要用于游戏挂机&#xff0c;但其潜力在海外电商领…

什么是虚拟线程?

1、典型回答 Java 中的虚拟线程&#xff0c;也叫做协程或“轻量级线程”&#xff0c;它诞生于JDK 19(预览 API)&#xff0c;正式发布于 JDK 21&#xff0c;它是一种在 Java 虚拟机(JVM)层面实现的逻辑线程&#xff0c;不直接和操作系统的物理线程一一对应&#xff0c;因此它可…

Anaconda配置系统环境

首先&#xff0c;右键此电脑&#xff0c;点击属性 点击高级系统设计 点击环境变量 点击环境变量中系统环境下的Path&#xff0c;双击 如下图&#xff0c;添加这四项即可&#xff0c;注意&#xff0c;这都是Anaconda的安装目录下的内容 在windowsR的cmd情况下&#xff0c;输入co…

leetcode LCR121.寻找目标值-二维数组

目录 问题描述示例具体思路思路一思路二 代码实现 问题描述 m*n 的二维数组 plants 记录了园林景观的植物排布情况&#xff0c;具有以下特性&#xff1a; 每行中&#xff0c;每棵植物的右侧相邻植物不矮于该植物&#xff1b; 每列中&#xff0c;每棵植物的下侧相邻植物不矮于该…

刷题DAY27 | LeetCode 39-组合总和 40-组合总和II 131-分割回文串

39 组合总和&#xff08;medium&#xff09; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates…

电脑中msvcp140_codecvt_ids.dll丢失的解决方法,实测有效的方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中最常见的就是缺少某个DLL文件。而msvcp140CODECVTIDS.dll就是其中之一。那么&#xff0c;msvcp140CODECVTIDS.dll是什么&#xff1f;msvcp140CODECVTIDS.dll文件属性又是什么呢&#xff1f;msvcp140C…

抖音小店怎么选品?从六点下手,才能选出爆款产品!

大家好&#xff0c;我是电商糖果 选品是做店的核心&#xff0c;它直接关系到店铺的流量和转化率&#xff0c;也就是店铺的收益。 这也是糖果在以往的文章中反复强调的&#xff0c;选品可以说非常重要了。 关于新手选品不知道从何下手&#xff0c;糖果自己总结了一下选品需要…

C++项目——集群聊天服务器项目(五)网络模块与业务模块

今天来正式书写集群聊天服务器网络模块与部分业务模块的代码 环境搭建C项目——集群聊天服务器项目(一)项目介绍、环境搭建、Boost库安装、Muduo库安装、Linux与vscode配置-CSDN博客 Json第三方库 muduo网络库 MySQL数据库 一、工程目录创建 项目通过CMake编译&#xff0c…

C语言例4-2:判断某些字符型变量中存放的是否为大写字母或数字字符。

代码如下&#xff1a; //判断某些字符型变量中存放的是否为大写字母或数字字符。 #include<stdio.h> int main(void) {int x1, x2, x3, x4; //数据定义语句char c1a, c2B, c31, c4!; //数据定义语句x1c1>A&&c1<Z; //表达式判断c1是否…

安卓studio连接手机之后,一两秒之后就自动断开了。问题解决。

太坑了&#xff0c;安卓studio链接手机之后。几秒之后就断开了。我以为是adb的问题&#xff0c;就重新安装了一下adb。并且在环境变量中配置了Path的路径。然而并没有什么用啊。 经过排查原来是数据心虚了。线的接触不良。导致你刚接通的瞬间有相对较强的电流是因为有瞬间高电压…

精酿啤酒:酿造工艺的细节与品质的关联

啤酒的酿造工艺是一个复杂而精细的过程&#xff0c;每一个环节都可能影响的品质和口感。Fendi Club啤酒作为一家注重品质和口感的品牌&#xff0c;在酿造工艺的细节方面有着严格的要求和杰出的技艺。 原料的选择是决定啤酒品质的重要因素之一。Fendi Club啤酒选用上好的大麦、水…

【日常记录】【CSS】css实现汉堡菜单

文章目录 1、介绍2、布局3、鼠标移入变成 X 1、介绍 在移动端或者响应式中&#xff0c;可能会遇到 三个横线 鼠标移动到的时候&#xff0c;会变成 一个 X 符号&#xff0c;这个就是汉堡菜单 2、布局 <style>* {margin: 0;padding: 0;box-sizing: border-box;}body {displ…

ros找不到生成的可执行文件[rosrun] Couldn‘t find executable named hello_world_cpp below

catkin_make之后source ./devel/setup.bash source之后运行节点的时候,ros找不到可执行文件&#xff08;其实tab键补不齐就没找到了&#xff09; 手动查找发现生成的可执行文件在build下不在devel/lib下&#xff0c;所以白source&#xff0c;压根找不到。 查找原因说是因为CMa…

基于 C++ STL 的图书管理系统213行

定制魏&#xff1a;QTWZPW&#xff0c;获取更多源码等 目录 一、实践项目名称 二、实践目的 三、实践要求 四、实践内容 五、代码框架参考 六、代码效果展示 七、完整代码主函数展示 一、实践项目名称 基于 C STL 的图书管理系统 二、实践目的 通过设计和实现一个基于…

NAT---网络地址转换技术

Network Address Translation 1、起源&#xff1a;ip地址不够用 2、作用&#xff1a;让私网地址映射成公网地址&#xff0c;进而访问网络。 3、私网Ip地址的范围&#xff1a; A类&#xff1a;10.0.0.0-10.255.255.255 B类&#xff1a;172.16.0.0-172.31.255.255 C类&…

【八股】Java 线程状态转化

线程一共有六种状态 1. NEW - 新建 public static void main(String[] args) throws ExecutionException, InterruptedException {Thread t new Thread(() -> {System.out.println("running");}, "t1");System.out.println(t.getState()); // 线程创…

【MySQL系列】Public Key Retrieval is not allowed

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…