Linux进程地址空间详解

文章目录

    • 前言
    • 一、程序地址空间
    • 二、感受虚拟地址的存在
    • 三、进程地址空间
    • 四、程序从磁盘加载到内存的过程
      • 4.1 物理地址和虚拟地址的区别
    • 五、写时拷贝
      • 5.1 解释fork()函数有两个返回值

前言

  • 我们在学习C/C++的时候用到的地址是什么地址呢?虚拟地址?物理地址?
  • 本文就来寻找一下答案~

一、程序地址空间

  • 程序地址空间的空间布局图

在这里插入图片描述

  • 从上面的图我们可以看出,程序地址空间中存在一些相关的区域:正文代码,初始化数据,未初始化数据,堆,共享区,栈,命令行和环境变量,内核空间,除了内核空间,其他空间都属于用户空间,所占的空间大小是3G

二、感受虚拟地址的存在

  • 我们可以用fork进程创建一个子进程,然后再定义一个全局变量,然后父进程和子进程同时访问全局变量然后进行同时观察地址
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>int g_val = 100;int main(){pid_t id = fork();if(id < 0){perror("fork");exit(-1);}else if(id == 0){// childprintf("This is child[%d],%d:%p",getpid(), g_val, &g_val);}else{// parentprintf("This is parent[%d],%d:%p",getpid(), g_val, &g_val);}sleep(1);return 0;
}
  • 可以观察到父进程和子进程的访问的地址和值是一样的,所以子进程和父进程共享同一个数据

在这里插入图片描述

  • 再来观察一个现象
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>int g_val = 50;int main(){pid_t id = fork();if(id < 0){perror("fork");return 0;
}
else if(id == 0){g_val = 100;printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);}else{sleep(3);printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);}sleep(1);return 0;
}
  • 我们发现,父子进程,输出地址是一致的,但是变量内容不一样!
  • 我们可以得出一个结论,这里所指的地址不可能是物理地址,因为同一个地址只能是同一个内容,不可能出现同一个地址存放两个不同的值
  • 其实这里的地址是虚拟地址,不是真正的物理地址

在这里插入图片描述

三、进程地址空间

  • 其实在每一个进程建立的时候,操作系统不仅会为进程创建一个PCB,同时还会为每一个进程创建一个进程地址空间。
  • 每一个进程都有自己独立的进程地址空间,那么这样系统中的进程地址空间就会非常多,操作系统就需要对这些进程地址空间进行管理和控制,而管理的本质就是先描述再组织,描述的意思就是为进程地址空间创建一个结构体。
  • 在Linux系统中,有一个结构体叫做:mm_struct,每一个进程都是相对独立,互不影响的,每一个进程中的PCBmm_struct都是相互独立的,这就是进程的独立性。

在这里插入图片描述


  • 进程地址空间中的结构和前面讲的程序地址空间的结构一样,其中都包含正文代码,初始化数据,未初始化数据,堆区,共享区和栈区,还有命令行参数和环境变量

  • 在实际中,每个区域都每一个区域都是由对应的startend来维护的,如果我们想改变对应区域的大小,我们可以通过设置对应区域的start和end进行修改即可,在每一个区域的start和end中会包含很多的地址,这个地址就是所谓的虚拟地址,不是物理地址,物理地址是存在于内存中的,不是存在进程地址空间的。

四、程序从磁盘加载到内存的过程

程序被编译但还没有被加载到内存时程序内部是否存在地址?

  • 代码被编译形成可执行程序之后是存在对应的地址的,也就是说程序中的每一段代码在程序中的位置已经确定,这个地址是代码在程序中的地址,与内存中的虚拟地址是没有任何关系的

程序被编译但还没有被加载到内存时程序内部是否存在区域?

  • 代码被编译成可执行程序之后,在可执行程序中是存在相关区域的,存在的区域有:正文代码,初始化数据区,未初始化数据区,命令行参数和环境变量,这时需要注意:并不存在栈区和堆区,栈区和堆区是要等程序加载到内存中才存在的

4.1 物理地址和虚拟地址的区别

  • 物理地址是在代码在真正的内存中存在的地址(位置)
  • 虚拟地址是指CPU直接能够访问到的地址,并不是相关代码在内存中的真实地址,这个虚拟地址的作用就是能够通过页表相关的映射关系转化成代码在内存中的物理地址
  • 因此,我们一旦有一个代码的虚拟地址还有页表的映射关系,其实就相当于我们有了代码在内存中的物理地址,虚拟地址和物理地址是通过页表建立联系的

在这里插入图片描述

  • 当一个进程运行起来的时候,每个进程都会分别创建PCB和mm_struct,每一个进程都独自拥有一个进程地址空间。
  • 页表是进程地址空间和物理内存之间存在的一个工具,主要作用就是负责利用其中虚拟地址和物理地址的映射关系实现虚拟地址和物理地址之间的相互转化,也就是说有了虚拟地址和页表,我就可以找到对应的物理地址,也就是相当于对应映射。

在这里插入图片描述

  • 上面的图就足矣说名问题,同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址

五、写时拷贝

  • 写时拷贝是指当数据被修改的时候,系统会在内存中重新为该数据开辟一块新空间,将该数据原来的内存拷贝放到新空间,然后再在新空间对该数据进行修改

  • 在我们前面的感受虚拟地址的存在的时候知道,父子进程访问同一个数据出现两个结果是因为有虚拟地址的存在,那么我们可以近一步讨论一下这个问题

  • 当系统识别到子进程想要修改该数据的时候,系统会为子进程在内存的另一个地方开辟一块新的空间,然后将该数据原来的值拷贝放到新空间,然后再在新空间对数据进行修改,这个新空间就是该变量在内存中实际存在的物理地址空间,此时操作系统会更新子进程中的页表映射关系,其中改变的是页表中原先映射关系的物理地址,让原先的物理地址更新为更改后的物理地址,

  • 因此,我们会发现,父子进程的页表中对该变量的虚拟地址是一样的,但是在子进程对该数据进行修改之后,子进程的页表被重新更新,更新之后映射出的物理地址就是不一样的,此时父子进程访问的其实是两个不同的物理空间中的内容,所以结果就会出现父子进程访问同一个虚拟地址出现不同的结果

在只读的情况下:

在这里插入图片描述

在写入的时候,进行写时拷贝

在这里插入图片描述

5.1 解释fork()函数有两个返回值

  • pid_d id是属于父进程栈空间的变量,fork()函数内部return会被执行两次,return的本质就是将保存在寄存器上的值写入到接收返回值的变量中, 当id = fork();的时候,谁先返回,谁就要发生写时拷贝,所以,同一个变量,会有不同的内容,本质是因为这个变量的虚拟地址是一样的,但是会有不同的物理地址。

好了,本文就到这里,感谢大家的收看🌹🌹🌹

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

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

相关文章

【无人机综合考试题】

1.请选择出哪一个功能选项&#xff0c;在手动遥控飞行时&#xff0c;可以改变各通道的操作灵敏度? 行程比例在手动遥控飞行时&#xff0c;可以改变各通道的操作灵敏度 用于起降的遥控器中 THR、ELE 通道分别控制多旋翼无人机的什么运动? AIL(左、右移动)RUD(左、右水平旋转…

Java基础【上】韩顺平(反射、类加载、final接口、抽象类、内部类)

涵盖知识点&#xff1a;反射、类加载、单例模式、final、抽象类、接口、内部类&#xff08;局部内部类、匿名内部类、成员内部类、静态内部类&#xff09; P711 反射机制原理 创建如下目录结构&#xff0c;在模块下创建src文件夹&#xff0c;文件夹要设置为Sources文件夹&…

红桃写作方便吗 #学习方法#微信#微信

红桃写作是一个非常好用的论文写作工具&#xff0c;它不仅方便快捷&#xff0c;而且非常靠谱&#xff0c;能够帮助用户轻松完成论文写作任务。不论是学生还是专业人士&#xff0c;都可以通过红桃写作轻松地完成论文的写作工作&#xff0c;大大提高工作效率。 首先&#xff0c;红…

多人协作的思考

有时候可能会有多人协作的需求&#xff0c;多人协作有很多实现方式 可以多人改&#xff0c;但是同时只有一人能改。这种不算纯粹的多人协作&#xff0c;偏权限控制。 飞书文档类的多人协作&#xff0c;大家都在同一个数据载体上修改。 git式的多人协作&#xff0c;没人都有一…

flutter->Scaffold左侧/右侧侧边栏和UserAccountsDrawerHeader的使用

//appBar的 leading/actions 和 Scaffold的drawer/endDrawer 冲突只能存在一个 import package:flutter/material.dart;void main() {runApp(MyApp()); }class MyApp extends StatelessWidget {const MyApp({super.key});overrideWidget build(BuildContext context) {retur…

【docker常用命令】

1. 什么是docker Docker 是一种开源的容器化平台&#xff0c;用于开发、交付和运行应用程序。它允许开发人员将应用程序及其依赖项&#xff08;如库、环境变量、配置文件等&#xff09;打包到一个被称为容器的标准化单元中。这个容器包含了一切应用程序需要运行的所有内容&…

Python编程—Ajax数据爬取

Python编程—Ajax数据爬取 ​ 在浏览器中可以看到正常显示的页面数据&#xff0c;而使用requests得到的结果中并没有这些数据。这是因为requests获取的都是原始HTML文档&#xff0c;而浏览器中的页面是JavaScript处理数据后生成的结果&#xff0c;这些数据有多种来源&#xff…

使用 Suno 创作歌曲

Suno 是一款基于人工智能的音乐创作工具&#xff0c;可以帮助您轻松创作原创歌曲。 它可以根据您的歌词生成旋律、和弦和伴奏&#xff0c;并提供多种风格和情绪供您选择。 在本文中&#xff0c;我们将介绍如何使用 Suno 创作歌曲。 我们将使用以下步骤&#xff1a; 选择客制化…

蓝桥杯每日一题:扫雷

题目来源&#xff1a;第十三届蓝桥杯软件赛省赛 B组 在一个 n n n 行 m m m 列 的方格图中有些位置有地雷, 另外一些位置为空 请为每个空位置标一个整数, 表示周围八个相邻的方格中有多少个地雷 输入 : 输入的第一行包含两个整数 n n n , m m m 第 2 行 到 第 n 1 n 1 n…

windows 系统下(nacos1.x) nacos-1.1.3 链接数据库 mysql8.0 出错分析

** windows 系统下&#xff08;nacos1.x&#xff09; nacos-1.1.3 链接数据库 mysql8.0 出错分析 ** 1、首先以下方法亲测无效&#xff1a; 1&#xff09;需要在数据库 URL 链接配置信息中 添加 allowPublicKeyRetrievaltrue 无效 db.url.0**&allowPublicKeyRetrievalt…

算法-最短路径

图的最短路径问题是一个经典的计算机科学和运筹学问题&#xff0c;旨在找到图中两个顶点之间的最短路径。这种问题在多种场景中都有应用&#xff0c;如网络路由、地图导航等。 解决图的最短路径问题有多种算法&#xff0c;其中最著名的包括&#xff1a; 1.迪杰斯特拉算法 (1).…

NIO详解

前期处理 对应的思维导图地址: https://www.processon.com/view/link/62247e810e3e74108ca1b5d7 对应的 Github地址: https://github.com/yuejianli/NIO 依赖 全局 pom.xml 依赖 <dependencies><dependency\><groupId\>junit</groupId\><artif…

AWTK T9 输入法实现原理

1. T9 输入法的中文字典数据 网上可以找到 T9 输入法的中文字典数据&#xff0c;但是通常有两个问题&#xff1a; 采用 GPL 协议&#xff0c;不太适合加入 AWTK。 只支持单个汉字的输入&#xff0c;不支持词组的输入。 经过考虑之后&#xff0c;决定自己生成 T9 输入法的中…

Mamba复现与代码解读

文章目录 环境配置demo推理源码解析参数解读Mamba块&#xff08;Mamba Block&#xff09;状态空间模型(SSM)选择性扫描算法&#xff08;selective_scan&#xff09;前向传播&#xff08;forward&#xff09; 均方根归一化 &#xff08;RMSNorm&#xff09;残差块&#xff08;Re…

集成学习 | 集成学习思想:Boosting

目录 一. Boosting思想1. Adaboost 算法1.1 Adaboost算法构建流程1.2 sklearn库参数说明 2. Gradient Boosting 算法2.1 Gradient Boosting算法构建流程2.2 Gradient Boosting算法的回归与分类问题2.2.1 Gradient Boosting回归算法均方差损失函数绝对误差损失函数 2.2.2 Gradie…

CAS(Compare-And-Swap)机制介绍

一、概念介绍 CAS&#xff08;Compare-And-Swap&#xff09;机制在C中是一种用于实现并发编程中同步和互斥的重要技术。CAS机制提供了一种原子操作&#xff0c;允许程序在不使用锁的情况下对共享变量进行读取、修改和写入。这种机制的核心思想是先比较再设置&#xff0c;即在修…

理论学习:ground-truth labels在深度学习中是什么意思

在深度学习中&#xff0c;"ground-truth labels"&#xff08;真值标签&#xff09;是指数据集中每个样本的正确答案或真实状态。这些标签是由人类专家提供的&#xff0c;代表了我们希望模型学习预测的准确结果。在训练深度学习模型时&#xff0c;真值标签被用作参照点…

【Linux】进程地址空间详解

前言 在我们学习C语言或者C时肯定都听过老师讲过地址的概念而且老师肯定还会讲栈区、堆区等区域的概念&#xff0c;那么这个地址是指的物理内存地址吗&#xff1f;这里这些区域又是如何划分的呢&#xff1f; 我们在使用C语言的malloc或者C的new函数开辟空间时&#xff0c;开辟…

Median of an Array(贪心策略,编程技巧)

文章目录 题目描述输入格式输出格式样例输入样例输出提交链接提示 解析参考代码 题目描述 给你一个由 n n n 个整数组成的数组 a a a 。 数组 q 1 , q 2 , … , q k q_1,q_2,…,q_k q1​,q2​,…,qk​ 的中位数是 p ⌈ k 2 ⌉ p⌈\frac {k}{2}⌉ p⌈2k​⌉ &#xff0c;其…

可解释性AI(XAI)

可解释性AI&#xff08;XAI&#xff09;旨在提高人工智能系统的透明度和可理解性&#xff0c;使人们更好地理解AI的决策过程和原理。随着AI技术的广泛应用&#xff0c;XAI成为了一个备受关注的重要领域。它不仅有助于建立人们对AI的信任&#xff0c;还可以帮助解决AI伦理和偏见…