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

进程地址空间

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

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

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

相关文章

【Java】HashSet集合用法

目录 HashSet 集合特点 示例代码 手写HashSet集合 HashSet 没有Get() HashSet 集合特点 HashSet 基于HashMap 来实现的&#xff0c;是一个不允许有重复元素的集合HashSet 允许有 null 值HashSet 是无序的&#xff0c;即不会记录插入的顺序HashSet集合实现了Set接口HashSet …

SpringCloud Alibaba【三】Gateway

Gateway配置与使用 前言新建gateway子项目pom.xml配置文件启动类访问接口方式 测试拓展 前言 在工作中遇到一种情况&#xff0c;一个父项目中有两个子项目。实际使用时&#xff0c;需要外网可以访问&#xff0c;宝信软件只能将一个端口号发布在外网上&#xff0c;所以需要运用…

什么是操作系统

如果你能大概了解下图&#xff1f;这个大概了解操作系统的样子&#xff0c;这是计算机的一些个裸件&#xff0c;了解这些对将来深入学习操作系统&#xff0c;是一个基础。 今天的内容&#xff1a;我们要建立操作系统的一个宏观轮廓 这个有黑色的&#xff0c;一条一条的&#…

Kubernetes技术与架构-存储 2

在Kubernetes集群中&#xff0c;一块持久化存储空间是可以被回收再利用&#xff0c;简称PV&#xff0c;即PersistentVolume&#xff0c;Pod实例需要使用PV的时候&#xff0c;可以使用PVC定义申请PV存储资源&#xff0c;PVC是PersistentVolumeClaim的简称&#xff0c;PV的申请分…

「实验记录」CS144 Lab0 networking warmup

文章目录 一、Motivation二、SolutionsS1 - Writing webgetS2 - An in-memory reliable byte stream 三、Results四、Source 一、Motivation 第一个小测试 webget 是想让我们体验并模拟一下在浏览器中键入 URL 后获得远程服务器传来的内容&#xff0c;这并没有太大的难度&…

【Oracle】Navicat Premium 连接 Oracle的两种方式

Navicat Premium 使用版本说明 Navicat Premium 版本 11.2.16 (64-bit) 一、配置OCI 1.1 配置OCI环境变量 1.1.2 设置\高级系统设置 1.1.2 系统属性\高级\环境变量(N) 1.1.3 修改/添加系统变量 ORACLE_HOME ORACLE_HOME D:\app\root\product\12.1.0\dbhome_11.1.4 添加系…

基于AI与物联网技术的智能视频监控系统架构剖析

智能视频监控系统正逐渐成为我们日常生活和工作中不可或缺的一部分。基于物联网的智能监控系统架构为我们在各个领域提供了更高效、智能化和安全的监控解决方案。本文将以旭帆科技EasyCVR视频监控云平台为例&#xff0c;介绍基于AI、物联网的智能监控系统的架构&#xff0c;并探…

电脑提示由于找不到vcruntime140.dll文件,教你四个解决方案

本文将介绍vcruntime140.dll文件的定义、作用以及丢失的原因&#xff0c;并提供四个解决方案来解决这个问题。 首先&#xff0c;让我们来了解一下vcruntime140.dll文件是什么。vcruntime140.dll是Microsoft Visual C Redistributable Package的一部分&#xff0c;它是运行使用…

业务设计——用户敏感信息展示脱敏及其反脱敏

业务需求 将用户敏感信息脱敏展示到前端是出于保护用户隐私和信息安全的考虑。 敏感信息包括但不限于手机号码、身份证号、银行卡号等&#xff0c;这些信息泄露可能导致用户个人信息的滥用、身份盗用等严重问题。脱敏是一种常用的保护用户隐私的方式&#xff0c;它的目的是减少…

IOC课程整理-6 Spring IoC 依赖注入

1 依赖注入的模式和类型 模式 类型 2 自动绑定&#xff08;Autowiring&#xff09; 官方定义 “自动装配是Spring框架中一种机制&#xff0c;用于自动解析和满足bean之间的依赖关系。通过自动装配&#xff0c;Spring容器可以根据类型、名称或其他属性来自动连接协作的bean&…

OpenCV官方教程中文版 —— 模板匹配

OpenCV官方教程中文版 —— 模板匹配 前言一、原理二、OpenCV 中的模板匹配三、多对象的模板匹配 前言 在本节我们要学习&#xff1a; 使用模板匹配在一幅图像中查找目标 函数&#xff1a;cv2.matchTemplate()&#xff0c;cv2.minMaxLoc() 一、原理 模板匹配是用来在一副大…

BUUCTF Reverse 新年快乐

下载文件先查壳&#xff0c;可以看到有UPX壳 用upx脱壳 拖到ida pro32&#xff0c;shiftF12查看字符串&#xff0c;看到关键字flag&#xff0c;双击进去 双击然后f5查看伪代码 main函数伪代码 关键函数&#xff1a; strncmp(const char *str1, const char *str2, size_t n)…

群智能算法之模拟退火算法

1.模拟退火算法简介&#xff1a; 2.模拟退火算法的关键点&#xff1a; &#xff08;1&#xff09;随机的更新可行解x,判断可行解x对应的函数值和原来函数值之间的大小&#xff1a;如果优于原来的函数值&#xff0c;则让新的可行解x为问题的解&#xff1b;否则以一定的概率(大于…

FL Studio21.2.0.3421最新汉化破解版中文解锁下载完整版本

音乐在人们心中的地位日益增高&#xff0c;近几年音乐选秀的节目更是层出不穷&#xff0c;喜爱音乐&#xff0c;创作音乐的朋友们也是越来越多&#xff0c;音乐的类型有很多&#xff0c;好比古典&#xff0c;流行&#xff0c;摇滚等等。对新手友好程度基本上在首位&#xff0c;…

【存储】lotusdb的原理及实现

最近看了lotusdb的源码。lotusdb是一个golang实现的嵌入式的持久化kv存储。 从整体设计上看&#xff0c;lotusdb采用了类似LSM树的架构&#xff0c;并采用了针对SSD的优化&#xff0c;将key和value分开存储。在此基础上&#xff0c;lotusdb将LSM树中存储key的SST使用B树或者ha…

WORD中的表格内容回车行距过大无法调整行距

word插入表格&#xff0c;编辑内容&#xff0c;换行遇到如下问题&#xff1a; 回车后行距过大&#xff0c;无法调整行距。 解决方法&#xff08;并行&#xff09;&#xff1a; 方法1&#xff1a;选中要调整的内容&#xff0c;菜单路径&#xff1a;“编辑-清除-格式” 方法2&am…

No173.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

Java SE 学习笔记(十八)—— 注解、动态代理

目录 1 注解1.1 注解概述1.2 自定义注解1.3 元注解1.4 注解解析1.5 注解应用于 junit 框架 2 动态代理2.1 问题引入2.2 动态代理实现 1 注解 1.1 注解概述 Java 注解&#xff08;Annotation&#xff09;又称Java标注&#xff0c;是JDK 5.0引入的一种注释机制&#xff0c;Java语…

Unity ScrollView最底展示

Unity ScrollView最底展示 问题方案逻辑 问题 比如在做聊天界面的时候我们肯定会使用到ScrollView来进行展示我们的聊天内容&#xff0c;那么这个时候来新消息的时候就需要最底展示&#xff0c;我认为这里有两种方案&#xff1b; 一种是通过算法每一条预制体的高度*一共多少…

汇编运算符和表达式

运算符&#xff1a; 汇编语言由表达式和运算符组成&#xff0c;运算符分为数值运算符和属性运算符。属性运算符面向变量或标号。 数值运算符&#xff1a; 算术运算符&#xff1a; 运算符类型 ✓ ( 正号 ) 、 -( 负号 ) ✓ ( 加 ) 、 -( 减 ) 、 *( 乘 ) 、 /( 除 ) 、 MO…