Linux下进程地址空间初步理解

news2024/11/18 19:48:17

进程地址空间

进程地址空间是操作系统为每个进程分配的一块内存空间,用于存储进程的代码、数据和堆栈等信息。进程地址空间是逻辑上独立而相互隔离的,每个进程拥有自己独立的地址空间,进程之间不能直接访问彼此的地址空间

  1. 代码段:存放可执行程序的机器指令,也称为文本段,也有可能包含一些只读的常数变量,例如字符串常量等。这些指令在程序运行时是只读的,保存程序的执行逻辑。

  2. 数据段:存放程序的全局变量、静态变量和常量,这些数据在程序运行时可以被修改。

  3. 堆:存放动态分配的内存,如使用malloc或new申请的内存,在程序运行时可以动态地进行内存分配和释放。

  4. 栈:用于存放函数调用所需的局部变量、函数参数和函数返回地址等。栈是一种先进后出的数据结构,每个函数调用会在栈上分配一块内存空间,函数返回后会释放该内存空间。

  5. 环境变量区域:存放程序的运行环境变量,如PATH、PWD、HOME等。

         


虚拟地址 (线性地址)

其实我们每个进程具有的地址空间并不是计算机内存,而是存放在计算机内存中。而且每个进程PCB内部有一个指针会指向这块进程地址空间。

#include<iostream>
#include<unistd.h>
using namespace std;

int g_val=10;
int main()
{
    pid_t id=fork();
    if(id==0)//子进程
    {
        int k=3;
        while(1)
        {
            cout<<"子进程:&g_val="<<&g_val<<",g_val="<<g_val<<endl;
            k--;
            if(k==0)
            {
                g_val=20;
                cout<<"子进程修改数据后-----"<<endl;
            }
            sleep(1);
        }

    }
    else//父进程
    {

        while(1)
        {
            cout<<"父进程:&g_val="<<&g_val<<",g_val="<<g_val<<endl;
            sleep(1);
        }
    }

    return 0;
}

就拿以上代码而言,g_val是一个已初始化的全局变量也就是进程地址空间的数据段区域,但是经过运行以后,我们发现该数据会有两个不同的值,这个是因为fork()函数会创建子进程,而子进程与父进程的代码是共享的,而数据是分别独立存放的,并且满足写时拷贝。但是为什么地址还是不变呢,同一个物理地址下的值不可能会有不同的值啊所以此时可以断定这一定不是物理地址,那就是虚拟地址 。

进程地址空间是不具有存储数据的能力的,所以我们的数据实际上还是会存放在计算机的内存当中的。 因为根据冯诺依曼体系结构可以知道CPU处理数据是通过与内存进行交互的。而我们的数据存在内存中,也有其数据对应的物理地址,所以此时我们进程地址空间上的虚拟地址想要访问对应物理地址的话,肯定是需要中间“桥梁”的。

页表(映射表)

这就是虚拟地址与物理地址交互的“桥梁”。操作系统会为每个进程构建一个对应的映射表。

 所以我们访问数据的过程其实是通过进程地址空间的虚拟地址去页表中寻找对应的物理地址,再访问物理地址所对应的数据。


所以接续上面的问题,为什么同一地址下的值不一样?

这其实因为这是虚拟地址,父进程在创建子进程时会将自己的的进程地址空间和页表都拷贝给子进程,而接下来无论是更改父进程的值还是子进程的值,并不会直接修改物理地址下的数据,因为此时的这个物理地址下的数据不止被一个进程所指,所以改变某个进程的值时会再单独在物理内存中开辟一个空间存放原来的值,然后再修改新空间的值(写时拷贝)。最后只需要改变页表上虚拟地址所对应的物理地址即可。从而达到了父子进程互不干扰的效果。所以两个页表中尽管虚拟地址相同,各自对应的物理地址也是不一样的,从而访问的数据也各不相同。 


管理进程地址空间(到底什么是进程地址空间)

我们的每一个进程地址空间都是经过区域分区的,每个区域的数据种类不同,而为了对进程地址空间做管理则必然是有一个类似于PCB(进程控制块)的的结构体,而这个结构体的名称就是mm_struct,而这个结构体里用long long类型的变量存放了有关进程地址空间的所有区域地址划分(也就是每个区域(例如栈区)的起始位置),而区域之间的地址可以被我们直接用来使用,也正是虚拟地址。而进程PCB中也有一个指针指向这个结构体。


所以此时对进程地址空间就有了一个全新的理解,进程地址空间其实就是mm_struct这样的内核数据结构

为什么要有进程地址空间和虚表

我们的虚表存在的目的就是将虚拟地址和内存的实际地址映射起来,并且提供数据的权限等作用,而我们为什么需要进程地址空间呢,直接将可执行程序的代码和数据存在内存,并直接访问内存不更好嘛?非也非也!

  • 我们知道可执行程序在运行时加载的的所有代码和数据并不是存在进程地址空间的,而是存在计算机的内存当中的。而内存中存放的数据并不一定是像进程地址空间一样将不同数据进行划分,而是可以将代码数据存在内存任意的空闲位置处。所以数据如果存在内存中的话是十分随意地,因此进程地址空间存在的第一个目的是:让所有进程都以同一种方式看待内存空间数据分布,并且能够将内存中无序的数据代码映射到地址空间时划分的井然有序。所以接下来即使进程挂起或代码数据被切换的话都会影响进程代码数据的物理地址,但是并不会影响其虚拟地址,所以进程PCB所记录的进程地址空间也不受影响。
  • 我们知道进程地址空间的代码段是只读的,而数据段是可读可写的,所以每个区域的数据访问权限并不是相同的,所以页表的每一个映射行关系里其实还有一个权限字段,存放的就是该地址下数据的访问权限字段。所以这样就可以防止程序意外访问或修改其进程的内存数据
  • 将进程管理和内存管理解耦




进程切换的理解 

我们知道每个进程的地址空间都有自己所对应的页表,可内存中肯定不止一个进程的,那么当进程运行,CPU调度该进程时是如何将该进程地址空间与自己的页表对应起来的呢???        其实CPU中有一个寄存器CR3里存放着进程地址空间所对应的页表地址(物理地址),所以当进程在切换运行时,寄存器CR3所存的页表地址都是不一样的,所以该寄存器里的内容肯定就在该进程的硬件上下文 中。

进程的硬件上下文不仅仅是一个寄存器。硬件上下文是一个包含多个部分的数据结构,它记录了进程在当前执行位置和状态的各种硬件信息。例如CPU寄存器记录了进程在执行时各个寄存器的状态,如通用寄存器、程序计数器(用于存储当前指令执行位置的寄存器)等)、内存页表等进程PCB中包含了记录进程硬件上下文的信息,并且在进程切换时用于保存和恢复进程的硬件上下文(简单来说就是当某个进程被CPU调度时,该进程PCB就会将有关该进程的上下文数据都导入进程硬件上下文当中,并且继续执行该进程的后续代码数据,而当进程切换出CPU时再将该进程硬件上下文的数据都拷贝到进程PCB中保存起来便于下一次的调度)。

缺页中断的部分理解

其实我们的页表映射行中还有一个字段信息:标识着该物理地址对应的空间是否在内存中分配给该数据以及该空间是否有内容。

首先我们要知道在程序执行之前,操作系统会为进程分配一段虚拟地址空间,然后在程序执行过程中将其映射到物理地址上。当我们的虚拟地址要被操作系统访问了,那么就会判断页表中字段信息的数据状况,如果页表字段信息中标识的内存和内容都是无的话,此时的访问请求就会暂停,但是还没完,操作系统会先在物理内存中开辟空间,在可执行程序中找到该虚拟地址所要访问的数据代码段落,并将该代码段和数据加载到开辟的内存当中,此时将物理地址填充到页表中,然后把标志字段信息的内容修改成内存已分配,内容已填充。最后访问请求就不再是暂停标志,所以可以继续访问数据信息。(这属于内存管理,进程并不知道该过程)

所以我们执行一个程序的时候并不是将程序的所有数据全部一下子加载进内存当中(全部加载内存不一定放得下)而是分部分的加载进内存,也就是取决于操作系统想要访问的数据。


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

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

相关文章

<多线程章节四>如何使用synchronized解决线程不安全问题(原子性、内存可见性…)等等

文章目录 &#x1f4a1;专栏导读&#x1f4a1;文章导读&#x1f490;线程不安全示例&#x1f490;锁的特性&#x1f490;产生线程不安全的原因&#xff1a;&#x1f490;加锁的三种方式&#xff1a; &#x1f4a1;专栏导读 本篇文章收录于多线程&#xff0c;也欢迎翻阅博主的其…

mavros黑白名单设置

链接: mavros设置黑白名单 设置mavros黑白名单主要是通过插件的参数进行设置&#xff0c;如下&#xff1a; 这里是在px4_pluginlists.yaml参数文件中设置 plugin_blacklist: # common - safety_area - 3dr_radio - actuator_control - hil_controls - ftp - global_position …

表的约束【MySQL】

文章目录 什么是约束DEFAULT&#xff08;默认约束&#xff09;NULL 与 NOT NULL&#xff08;非空约束&#xff09;COMMENT&#xff08;注释约束&#xff09;ZEROFILL&#xff08;零填充约束&#xff09;UNIQUE&#xff08;唯一键约束&#xff09;*PRIMARY KEY&#xff08;主键约…

Windows 10/11如何恢复永久删除的文件?

数据丢失在我们的工作生活中经常发生。当你决定清理硬盘或U盘时&#xff0c;你会删除一些文件夹或文件。如果你通过右键单击删除文件&#xff0c;则可以很容易从回收站恢复已删除的文件。但是&#xff0c;如果你按Shift Delete键、清空回收站或删除大于8998MB的大文件夹&#…

“停车费”用英语怎么说?千万不要说Stop car money!柯桥BEC商务英语学习

“200块的大餐说吃就吃 20块的停车费不是要我命吗” 年轻人主打一个该省省、该花花 说到“停车费”你知道用英语怎么说吗 难道是“stop car money”? 哈哈&#xff0c;这样说老外表示15857575376太中式啦&#xff01; C姐教你地道的英语表达 01 “停车费”用英语怎么说&a…

Python中如何使用ThreadPoolExecutor一次开启多个线程

目录 一、ThreadPoolExecutor的创建与使用 二、处理并发执行结果 三、异常处理 五、使用多线程注意事项 总结 在Python中&#xff0c;ThreadPoolExecutor是concurrent.futures模块提供的一种线程池类。它能够以线程的形式执行可调用对象&#xff0c;并允许您在执行过程中获…

教你如何帮助孩子做好时间管理,不再需要重复提醒!

给大家推荐一个小工具&#xff0c;不起眼 但是经过几个月的使用 发现相见恨晚 我家熊孩子怎么也改不掉的拖沓毛病 竟然被它治好了 经常会听到姐妹抱怨 自己家娃有“假期拖延症” 明明十几分钟就能写完的作业 一会说肚子疼想上厕所 一会又拿出铅笔刀要削铅笔 非得拖拖拉…

安卓开发实例:首页

导航菜单&#xff0c;点击按钮跳转。 activity_main.xml <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayoutxmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools&quo…

c++ 构造函数与析构函数(详解)

目录 目录&#xff1a; 1:构造函数 2:析构函数 前言&#xff1a;我们知道c使用起来是比c语言方便的&#xff0c;那么为啥比他使用起来简单&#xff0c;这里我们就不得不提及我们c中默认成员函数了&#xff0c;是它们默默的承担了所有。 下面让我们先来学习前两个默认成员函数:…

JavaScript基础知识18——逻辑运算符之短路运算

哈喽&#xff0c;大家好&#xff0c;我是雷工。 本节学习JavaScript基础知识——逻辑运算符中的短路运算&#xff0c;以下为学习笔记。 规则&#xff1a; 1、如果是&&运算&#xff0c;只要遇到false&#xff0c;就立即短路&#xff0c;不会再执行了&#xff0c;直接返回…

在声明和定义的一些小坑

1、静态成员变量的初始化 静态成员变量声明在 .h 头文件文件中&#xff0c;初始化应该在 .cpp 源文件中 就会出现"找到一个或多个多重定义的符号",下面的错误 class MyString{public:typedef char* iterator;typedef const char* const_iterator;iterator begin();…

复古风再现:探索70年代风格的室内设计在当今的复兴之路

20 世纪 70 年代的室内设计趋势正在卷土重来。大地色调、有趣的多色概念&#xff0c;以及低矮的软家具&#xff0c;都是当前的流行趋势。今年 2 月&#xff0c;许多室内设计师也表达了类似的观点&#xff0c;他们都在追捧备受诟病的棕色。当时的设计风趣、性感&#xff0c;但又…

YOLO目标检测——红外车辆行人数据集【(含对应voc、coco和yolo三种格式标签+划分脚本+训练教程】

实际项目应用&#xff1a;智能驾驶、智能监控、军事应用监控通过红外传感器采集车辆和行人的红外图像&#xff0c;然后使用目标检测算法对图像进行处理和分析&#xff0c;以识别道路上的车辆和行人。数据集说明&#xff1a;&#xff0c;真实场景的高质量图片数据&#xff0c;数…

Win11安装ise14.7~不需要虚拟机了~

之前一直无法在win11上安装ise14.7&#xff0c;网上搜索也无果&#xff0c;所有一直vmware虚拟机使用。直到最近看了水木上jesce的回复&#xff0c;试了下果然可以直接安装使用的。 步骤如下即可&#xff1a; 1.安装时切勿勾选最后一项&#xff0c;Enable WebTalk to send so…

Stable DiffusionAI绘画作品展示

参考链接&#xff1a; https://chat.xutongbao.top/

C语言实现图形界面创建按钮

文章目录 其他章节创建按钮指定按钮显示的文本 按钮样式 其他章节 开始之前&#xff0c;需要学习以下章节&#xff1a; 创建窗口 窗口过程函数 创建按钮 要在窗口上显示一个按钮&#xff0c;我们可以在窗口过程函数中处理 WM_CREATE 消息&#xff0c;在该消息中创建按钮并设…

我是如何走上测试管理岗的

最近有小伙伴问了一个问题&#xff1a;他所在的测试团队规模比较大&#xff0c;有 50 多个人&#xff0c;分成了 4 ~ 5 个小组。这位同学觉得自己的技术能力在团队里应该属于比较不错的&#xff0c;但疑惑的是在几次组织架构调整中&#xff0c;直属领导一直没有让他来管理一个小…

优先级反转,优先级继承和优先级天花板协议

优先级反转 优先级反转是RTOS&#xff08;实时操作系统&#xff09;会遇到的一个问题&#xff0c;简单来说就是由于调度原因&#xff0c;让原本优先级较高的任务慢于优先级较低的任务完成&#xff0c;比如下面这种情况&#xff0c;任务1、2、3的优先级依次升高&#xff0c;其中…

Jetpack:019-Jetpack的导航二(传递数据)

文章目录 1. 知识回顾2. 使用方法2.1 通过参数传递数据2.2 获取参数中的数据2.3 共享导航控制器 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack中导航相关的内容&#xff0c;本章回中 继续介绍导航相关的内容。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧…

注意力机制、Transformer模型、生成式模型、目标检测算法、图神经网络、强化学习、深度学习模型可解释性与可视化方法等详解

采用“理论讲解案例实战动手实操讨论互动”相结合的方式&#xff0c;抽丝剥茧、深入浅出讲解注意力机制、Transformer模型&#xff08;BERT、GPT-1/2/3/3.5/4、DETR、ViT、Swin Transformer等&#xff09;、生成式模型&#xff08;变分自编码器VAE、生成式对抗网络GAN、扩散模型…