进程地址空间(Linux)

进程地址空间

  • 一、引入概念
    • 1. 程序的地址分布
    • 2. 线性地址和物理地址
  • 二、进程地址空间
    • 1. 初步认识
    • 2. 地址空间和物理内存的联系
    • 3. 区域划分
    • 4. 拓展——关于“线”
  • 三、进一步理解进程地址空间
  • 四、页表
  • 总结

一、引入概念

1. 程序的地址分布

测试代码:

#include <stdio.h>                                                                                                                                                                                                                          
#include <stdlib.h>    
    
//已初始化全局数据区    
int d = 0;    
    
//未初始化全局数据区    
int c;    
    
int main(int argc, char* argv[], char* env[])    
{    
    //栈区    
    int a = 0;    
    //堆区    
    int* p = (int*)malloc(sizeof(int));    
    //已初始化静态区    
    static int b = 0;    
    //未初始化静态区    
    static int e;    
    //常量区    
    const char* str = "hello Linux";    
    
    printf("stack addr: %p\n", &a);    
    printf("heap addr: %p\n", p);    
    printf("uninit g_val addr: %p\n", &c);    
    printf("init g_val addr: %p\n", &d);    
    printf("uninit static val:%p\n", &e);    
    printf("init static val:%p\n", &b);    
    printf("read only string addr: %p\n",str);    
    printf("code addr: %p\n", main);    
    
    int i = 0;    
    for(; argv[i]; i++)    
    {    
        printf("argv[%d]:%p\n", i, argv[i]);    
    }    
    
    for(i = 0; env[i]; i++)    
    {    
        printf("env[%d]:%p\n", i, env[i]);    
    }    
    
    return 0;    
} 

测试结果分析:
测试结果分析

注:根据系统的不同,可能得到的结果有一定的区别,就如同上面初始化数据区和未初始化数据区位置的结果有出入的原因分析一样。

2. 线性地址和物理地址

物理地址: 指计算机中实际的硬件内存地址,它是由硬件设备(如内存控制器)直接生成的。物理地址是一个唯一的标识符,用于访问计算机的物理内存。
物理地址与虚拟地址是不同的概念。虚拟地址是进程地址空间中的地址,它是由操作系统分配给进程的,并且可以通过地址转换机制映射到物理地址。

测试代码和结果:
测试和结果

结论:

  1. 变量的内容不一样,所以父子进程输出的不是同一个变量
  2. 地址值是一样的,说明该地址绝对不是物理地址。
  3. 所以, 在Linux地址下,这种地址叫做虚拟地址(线性地址)。在C/C++语言所看到的地址,全部都是虚拟地址,物理地址用户看不到,由OS统一管理。OS负责把虚拟地址转换成物理地址。

注: 回顾之前的知识有个问题没解决,就是fork创建子进程。如果fork成功,给父进程返回子进程的pid,给子进程返回0。 其中我们没有说一个变量id是如何存储两个值的,那么现在就可以理解了,因为不是同一个物理地址。
根据上面的结论,就可以得出:在使用fork函数的时候,返回值有两个分别是0和子进程的PID。得出如何一个变量(id)存在两个值。

二、进程地址空间

1. 初步认识

这里我们要进一步认识 ———— 进程地址空间

进程地址空间的地址就是虚拟地址
图例:和第一个例子的C/C++中程序内存区域划分那个图一致,都是抽象的进程地址空间。
进程地址空间

认识:

  1. 程序员在写代码中访问的指针的地址就是这个虚拟地址。而虚拟地址需要通过地址转换机制(也就是页表,后面讲)映射到物理地址上。
  2. 每个进程系统都会提供一个进程地址空间。实际是系统对该进程创建的结构体对象(后面讲)

2. 地址空间和物理内存的联系

解读fork创建进程那段代码,我们来认识进程地址空间、页表和物理地址空间的关系

#include <stdio.h>    
#include <unistd.h>    
    
int main()    
{    
    pid_t id = fork();    
    if(id < 0)    
    {    
        perror("fork");    
        return 0;    
    }    
    else if(id == 0)    
    {    
        //child    
        printf("child proc: fork return:%d  &id: %p\n", id, &id);    
    }    
    else    
    {    
        //father    
        printf("father proc: fork return:%d &id: %p\n", id, &id);                                                                                                                                                                           
    }    
    return 0;    
} 

解析:

  1. fork函数创建完子进程未返回时(此时id还没有存两个值)

图解

  • 父进程会复制自身的所有资源(包括代码、数据、打开的文件等)给子进程,并为子进程分配一个独立的进程ID。
    此时进程id指向同一个物理地址

注: OS为了提高效率,在创建子进程时会使用写时拷贝(Copy-on-Write)技术。这意味着在创建子进程时,并不会立即复制父进程的所有资源,而是共享父进程的资源。只有当子进程或父进程试图修改这些共享资源时,操作系统才会进行实际的复制操作。
当父进程创建子进程时,操作系统会将父进程的页表项指向相同的物理内存页。这样,子进程和父进程共享相同的物理内存页,包括代码、数据和只读的共享库等。当子进程或父进程试图修改这些共享的资源时,操作系统会将被修改的页复制一份,然后将新的页分配给修改进程,使得修改进程有自己的独立副本。只有在需要修改资源时才进行复制,其他未被修改的页仍然是共享的,可以被多个进程共享使用

  1. fork创建完子进程并返回,给父进程返回子进程的pid,给子进程返回0(所以此时id就是两个值)

图解

  • OS给更改后的变量重新申请空间,使用写时拷贝技术。对子进程的页表修改部分进行拷贝,将修改后新的页再分配给子进程。

小结:同一个变量,地址相同,其实也只是虚拟地址相同,内容不同,其实就是被映射到不同的物理地址

3. 区域划分

在引入概念中的程序的地址分布中,说到栈,堆等区域的划分。

区域划分: 好处

  1. 防止越界,空间分配合理
  2. 访问的范围越界,直接进行报错
  3. 进程地址空间中的代码区、常量区和数据区在编译时就确定了其大小和位置。堆区和栈区是随着运行时变量的开辟和销毁,堆区和栈区的边界会动态变化
    堆区和栈区是在运行时动态分配和释放内存的。堆区用于存放动态分配的内存,由程序员手动申请和释放,其边界由操作系统维护。栈区用于存放局部变量和函数调用的上下文信息,由编译器自动分配和释放,其边界由编译器维护。

操作系统内部进程地址空间的结构体:

struct mm_struct 
{
	//....
	unsigned long total_vm, locked_vm, shared_vm, exec_vm;
	unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;
	
	unsigned long start_code, end_code, start_data, end_data;     
	/*维护代码区和数据区的字段*/
	
	unsigned long start_brk, brk, start_stack;       
	/*维护堆区和栈区的字段*/
	
	unsigned long arg_start, arg_end, env_start, env_end;  
	/*命令行参数的起始地址和尾地址,环境变量的起始地址和尾地址*/
	//....
};

认识:

  1. 在上面初步认识进程地址空间这一知识点最后,我们说到,进程地址空间实际就是系统对该进程创建的结构体对象。
  2. 所谓的进程地址空间,本质是一个描述进程可视范围的大小。存在各种的区域划分,而这种对线性地址划分,只需要start,end即可

在这里插入图片描述

4. 拓展——关于“线”

问题1:CPU,内存,输入输出设备如何交互?

  • 通过“线”进行交互
  • 线细分为:地址总线,数据总线,控制总线
  • 也可以分成两种:CPU内存连的线叫系统总线。内存和输入输出设备连的线叫IO总线

注:

  1. 地址总线(Address Bus):是用于传输内存地址的一组物理线路。它的作用是将CPU发出的内存地址信号传递给内存或其他外部设备。
  2. 数据总线(Data Bus):是用于传输数据的一组物理线路。它的作用是将CPU和内存、输入输出设备之间的数据进行传输。
  3. 控制总线(Control Bus):是用于传输控制信号的一组物理线路。它的作用是传递CPU发出的各种控制信号,如读写控制、时钟信号、中断请求等。

三者的联系:共同构成了计算机的总线系统,用于实现CPU与内存、输入输出设备之间的数据传输和控制。CPU通过地址总线发送内存地址,通过数据总线进行数据的读取和写入,通过控制总线发送各种控制信号。内存和外部设备通过这些总线接口与CPU进行通信。地址总线和数据总线的宽度决定了计算机的寻址能力和数据传输带宽,而控制总线则负责传递各种控制信号,协调计算机的工作。三种总线共同完成计算机的数据传输和控制操作,保证计算机的正常运行。

  1. 系统总线(System Bus):是用于连接CPU、内存和其他主要组件的一组总线。系统总线扮演着连接CPU和内存之间的桥梁,用于传输指令、数据和控制信号。
  2. IO总线(I/O Bus):是用于连接CPU和输入输出设备的一组总线。它是系统总线的一个扩展,专门用于处理输入输出操作。

两者的联系:都是计算机中用于数据传输和控制的总线系统。系统总线主要用于连接CPU、内存和其他主要组件,用于处理计算机的主要运算和数据传输。而IO总线则专门用于连接CPU和输入输出设备,用于处理输入输出操作。系统总线和IO总线都包括地址总线、数据总线和控制总线,共同构成了计算机的总线系统。系统总线和IO总线的宽度决定了计算机的寻址能力和数据传输带宽。

问题2:线是什么,为什么用线?
线是指用于传输电信号或数据的物理连接。线通常由导体(如金属)制成,用于连接不同的组件或设备,主要是以便它们之间进行数据传输和通信
线的使用具有以下优点:

  1. 传输速度快
  2. 可靠性高:线能够提供稳定的物理连接,确保数据的可靠传输,减少数据传输中的错误和丢失。

三、进一步理解进程地址空间

为什么有进程地址空间?

  1. 让所有的进程以统一的视角看待内存结构。
    • 如果没有:在PCB中记录代码和数据在物理内存的某个地址处,从哪里开始到那里结束等等,而且每一个进程都要做。可能有存在进程挂起,代码和数据要换出换入,就又要更改PCB。总而言之,如果没有,就显得冗余,不便于管理
  2. 增加进程虚拟地址空间,可以让我们访问内存的时候,增加一个转换的过程,在这个过程可以对我们的寻址请求进行审查,所以一旦异常访问,就可以直接拦截,该请求不会到物理内存,就可以保护物理内存。
  3. 因为有地址空间和页表的存在,将进程管理模块和内存管理模块进行解耦合。

进程的独立性理解
每个进程都有自己独立的内存空间、寄存器集合和执行上下文,彼此不会相互干扰或影响。
从以下几个方面理解进程独立性:

  1. 内存隔离:每个进程都有自己独立的进程地址空间,进程之间的内存是相互隔离的。进程在申请内存时,本质上是OS申请的,由OS决定是否分配给进程空间,而进程在申请内存之间没有联系。
  2. 寄存器隔离:每个进程都有自己的寄存器集合,用于保存进程的执行上下文和临时数据。不同进程之间的寄存器是相互独立的,一个进程的寄存器状态不会影响其他进程的执行。
  3. 进程间通信:虽然进程具有独立性,但有时候进程之间需要进行通信和协作。操作系统提供了一些机制,如管道、消息队列、共享内存等,用于实现进程间的通信。通过这些机制,进程可以安全地进行数据交换和共享,而不会破坏彼此的独立性。
  4. 调度和资源管理:操作系统负责对进程进行调度和资源管理,确保每个进程都能够公平地获得CPU时间和其他资源。每个进程都有自己的调度优先级和资源限制,操作系统根据这些信息来进行调度和资源分配,保证进程的独立性和公平性。

注: 物理地址实际上也是由操作系统进行分配与管理的,由于页表的存在,建立了映射关系,可以将虚拟地址与物理地址联系起来,但进程与操作系统还是各管各的,只不过通过页表的修改而将虚拟地址与物理地址统一起来。

四、页表

页表

认识:

  1. 页表记录的信息包括权限,让修改到一些只读的权限时,会报错
  2. 页表的地址是物理地址,进程加载到CPU上,页表进行加载时,页表的地址会放到cr3寄存器中,属于进程上下文
  3. 在子进程拷贝父进程的页表时,栈区的地址权限可能会发生转变。通常,父进程的栈区是可写的,它需要在运行时动态地分配和修改栈帧。但是,在子进程中,为了保证进程的独立性和隔离性,OS可能会将栈区的权限设置为只读或不可访问。目的是防止子进程修改父进程的栈数据,如果子进程需要修改栈区,OS帮子进程申请一块空间,并更改物理地址和页表相应的权限。
  4. 页表中有存不存在内存中的问题,1表示存在0表示不存在

页表的当前权限和实际权限发生冲突时,就会触发缺页中断
页表的执行时不存在也会发生冲突时,就会触发缺页中断

注:
惰性加载:惰性加载(按需加载)是一种内存管理策略。它的核心思想是在需要使用数据或代码时才将其加载到内存中,而不是一次性将所有内容都加载进内存。当进程访问虚拟地址时,OS会先检查页表中对应的物理地址是否已经在内存中。如果不在,OS会触发缺页中断,表示所需的数据或代码当前不在内存中。在缺页中断处理过程中,OS会将缺失的页面从磁盘或其他存储介质中加载到内存中,并更新页表中的映射关系。然后进程继续执行,并使用已加载到内存中的数据或代码。

总结

进程 = 内核数据结构(task_struct&&mm_struct&&页表)+ 程序的代码和数据

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HttpHeaders 源码中headers成员变量为什么声明为final

源码如下 public class HttpHeaders implements MultiValueMap<String, String>, Serializable {private final Map<String, List<String>> headers;public String getFirst(String headerName) {List<String> headerValues (List)this.headers.get(…

STM32标准库开发—W25Q64详细介绍

W25Q64简介 Flash编程原理都是只能将1写为0&#xff0c;而不能将0写成1.所以在Flash编程之前&#xff0c;必须将对应的块擦除&#xff0c;而擦除的过程就是将所有位都写为1的过程&#xff0c;块内的所有字节变为0xFF.因此可以说&#xff0c;编程是将相应位写0的过程&#xff0c…

【Java发送邮箱】spring boot 发送邮箱

导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId> </dependency> 2.在properties配置邮箱 # 发件人QQ号 spring.mail.username2508575653qq.com # QQ邮箱授权码 sp…

EIGRP实验

实验大纲 一、基本配置 1.构建网络拓扑结构图 2.路由器基本配置 3.配置PC 4.测试连通性 5.保存配置文件 二、配置EIGRP 1.查看路由表 2.配置EIGRP动态路由 3.查看路由器路由表 4.测试网络连通性 5.查看所有路由器的路由协议 6.保存配置文件 三、配置OSPF 1.配置…

vue+draggable+el-upload上传图片拖拽重排方法

vuedraggableel-upload上传图片拖拽重排方法 1.html <el-row><el-col><el-form-item label"添加视频/图片" prop"device_id"><div class"image-upload"><draggable v-model"fileList" update"dataDr…

外包干了2个月,技术反而退步了...

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入广州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

OpenHarmony—类型转换仅支持as T语法

规则&#xff1a;arkts-as-casts 级别&#xff1a;错误 在ArkTS中&#xff0c;as关键字是类型转换的唯一语法&#xff0c;错误的类型转换会导致编译时错误或者运行时抛出ClassCastException异常。ArkTS不支持使用语法进行类型转换。 当需要将primitive类型&#xff08;如num…

2.4.4 代理一个TCP客户端(示例补充)

2.4.4 代理一个TCP客户端 不能直接访问的目标网站&#xff1a; package mainimport ("io""log""net" )// echo is a handler function that simply echoes received data. func echo(conn net.Conn) {defer conn.Close()// Create a buffer to s…

假期刷题打卡--Day15

1、MT1152韩信又生气了 韩信点兵(大于10人)&#xff0c;三个三个一排少1个人&#xff0c;五个五个一排又少1个人&#xff0c;七个七个一排还少1个人。韩信生气了&#xff0c;从别的队伍里调来一个人!这样不管是三个一排五个一排还是七个一排都完美了。问原本最少应该有多少人。…

《从零开始制作消除游戏:基于Web技术的简单教程》

在撰写《从零开始制作消除游戏&#xff1a;基于Web技术的简单教程》这篇博客时&#xff0c;主要的目标是提供一个清晰、逐步的指南&#xff0c;帮助读者从零开始创建自己的消除游戏。 游戏逻辑实现 游戏板设计与初始化&#xff1a;描述如何创建游戏板的数据结构&#xff0c;以…

机器学习算法(一)

一、线性回归 线性回归&#xff08;Linear Regression&#xff09;可能是最流行的机器学习算法。线性回归就是要找一条直线&#xff0c;并且让这条直线尽可能地拟合散点图中的数据点。它试图通过将直线方程与该数据拟合来表示自变量&#xff08;x 值&#xff09;和数值结果&am…

遇到继需证件照的时候怎么办?

你是否曾经遇到过这样的情况&#xff1a;急需一张证件照&#xff0c;却没有时间去照相馆或复印店&#xff0c;而且手头也没有现成的照片。这时候&#xff0c;你可能会感到很困扰&#xff0c;不知道该怎么办才好。别担心&#xff0c;今天我将为你揭示如何在短短一分钟内制作出自…

YOLOv8优化策略:分层特征融合策略MSBlock | YOLO-MS ,超越YOLOv8与RTMDet,即插即用打破性能瓶颈

🚀🚀🚀本文改进:分层特征融合策略MSBlock,即插即用打破性能瓶颈 🚀🚀🚀在YOLOv8中如何使用 1)作为MSBlock使用;2)与c2f结合使用; 🚀🚀🚀YOLOv8-seg创新专栏:http://t.csdnimg.cn/KLSdv 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定科研; 1)手把…

ANN论文总结

本文主要是个人笔记&#xff0c;记录与存储相关的ANN工作&#xff0c;想着写都写了不如发出来与大家分享&#xff0c;大多写得比较简单有些稍微详细一点&#xff0c;内容仅供参考。 CognitiveSSD S. Liang, Y. Wang, Y. Lu, et al. Cognitive SSD: A Deep Learning Engine for…

光纤接口类型

光纤接口 网络设备基础知识 文章目录 光纤接口前言一、光纤接口二、光纤接口的优缺点总结前言 不同的接口类型适用于不同的光纤传输系统和应用需求。在选择光纤设备时,需要根据实际需求和系统要求选择适当的光纤接口类型。 一、光纤接口

MATLAB环境下使用训练好的卷积神经网络进行大地电磁数据噪声抑制

大地电磁MT是一种比较成熟的地球物理勘探方法&#xff0c;通过计算地面测量的正交电场分量和磁场分量的扰动值研究地下介质的电性结构。MT在油气和工程勘探领域得到了广泛应用。但是由于该方法以天然电磁场为场源&#xff0c;存在地面信号弱和源激发随机的缺点&#xff0c;极易…

(27)Linux信号的产生核心转储---初步认识信号

一、信号入门 1. 生活角度的信号 你在网上买了很多件商品&#xff0c;再等待不同商品快递的到来。但即便快递没有到来&#xff0c;你也知道快递来临时&#xff0c; 你该怎么处理快递。也就是你能“识别快递”当快递员到了你楼下&#xff0c;你也收到快递到来的通知&#xff0…

Apollo Cyber RT:引领实时操作系统在自动驾驶领域的创新

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…

uniapp状态管理Vuex介绍及vuex核心概念

状态管理Vuex Vuex 是什么&#xff1f; Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 uni-app 内置了 Vuex 什么是“状态管理模式”&#xff1f; <!…

x-cmd pkg | haxor-news - Hacker News CLI

目录 简介首次用户功能特点进一步探索 简介 haxor-news 是一个用于在终端上查看 Hacker News 的内容。它可以让你在命令行查看/过滤 Hacker News 的帖子、评论、用户信息等&#xff0c;如过去 60 分钟内发布的最新评论。 Hacker News 是一家由 Paul Graham 创建的关于计算机黑…