【Linux】进程地址空间
创始人
2024-04-09 22:11:30
0


目录

一、虚拟地址

二、对进程地址空间的理解

三、32位下的进程地址空间

那么进程如何找到内存中的数据呢?

四、为什么要通过虚拟地址映射的方式访问物理地址


一、虚拟地址

先看一段父子进程共存的程序,由子进程对全局变量grobal_val进行修改:

#include 
#include 
int grobal_val=10;
int main()
{pid_t id=fork();if(id==0){int cnt=0;while(1){printf("子进程:pid=%d,ppid=%d | grobal_val=%d,&grobal_val=%p\n",getpid(),getppid(),grobal_val,&grobal_val);sleep(1);++cnt;if(cnt==10){grobal_val=200;printf("子进程已更改全局变量grobal_val\n");}}}else if(id>0){while(1){printf("父进程:pid=%d,ppid=%d | grobal_val=%d,&grobal_val=%p\n",getpid(),getppid(),grobal_val,&grobal_val);sleep(1);}}else {printf("fork error\n");return 1;}return 0;
}

父子进程谁先执行不确定,由系统进行调度。

当子进程将全局变量grobal_val由10改为200,我们可以看到,父子进程的grobal_val的地址相同,但是父子进程从这个地址中获取的值却并不相同!

从同一块物理地址中取出的值是相同的,所以这个程序取出的地址(指针)并不是物理地址,而是虚拟地址(线性地址、逻辑地址)。注:逻辑地址指可执行程序编译完成后内部函数、变量的地址。逻辑地址有两种表示方法,一种是各个区域地址递增,另一种是每个区域的地址都从零偏移量开始(这种是比较老的表示方式)。

在Linux中的逻辑地址是第一种表示方式,所以Linux中逻辑地址就是虚拟地址。

之前学习的C/C++内存区域,是一块虚拟内存空间,每个进程有它自己的虚拟内存空间,即进程地址空间。所以上面的代码用fork创建子进程,因为子进程是父进程的拷贝,父子进程的grobal_val虽然虚拟地址一样,但会被映射到不同的物理地址上。

当grobal_val未被改变时,父子进程映射同一块grobal_val的物理地址,一旦父子进程的一方对共享数据进行修改,由于进程的独立性,操作系统会在物理内存中再开辟一块空间,并拷贝原数据,提出修改的进程的页表映射关系将会被改变,然后再让进程对数据进行修改,所以我们看到父子进程的数据并不一样。这种技术称为写时拷贝,对不同进程的数据进行分离

二、对进程地址空间的理解

1、进程它自己会认为它独占CPU资源,但其实并不是。因为进程以时间片轮转的形式占用CPU资源,时间一到,马上从运行状态进入休眠状态,实质上是通过虚拟地址空间,让进程认为它独占CPU资源。

2、进程地址空间是操作系统给进程开辟的一块虚拟内存空间,这块空间用内核的一种数据结构来描述、组织。

操作系统给每个进程一块4GB的虚拟内存,进程每次想使用,按需申请即可,但不会全部给进程。(注意这里给的是虚拟内存,就像老板给员工画饼一样)

对Linux操作系统中进程的理解中提到过,进程使用进程控制块task_struct结构体进行管理,同样的,每个进程地址空间也需要被管理,管理进程地址空间的结构体叫mm_struct,task_struct中有一个指针指向自己的mm_struct。

mm_struct伪代码:

struct mm_struct
{uint32_t code_start,code_end;uint32_t data_start,data_end;uint32_t heap_start,heap_end;uint32_t stack_start,stack_end;······//存储进程地址空间各区域的起始位置
};

三、32位下的进程地址空间

地址空间中的最小单元是字节,所以在32位系统下共有2^(32)个地址空间,也就是4GB。

mm_struct结构体对象中存放各个区域的起始位置,栈区堆区的动态调整,本质上是修改各个区域的起始地址。

那么进程如何找到内存中的数据呢?

操作系统将进程中的虚拟地址通过页表映射到内存,找到对应的物理地址。

四、为什么要通过虚拟地址映射的方式访问物理地址

1、直接访问物理内存是非常不安全的,例如越界操作、恶意进程读取等。

2、页表会拦截不合理的请求,可以保护物理内存,防止恶意进程的访问 。

所以写代码出现野指针、内存越界等情况并不会造成操作系统的崩溃。

3、进程地址空间的存在,可以让进程和进程间的代码进行解耦(互不干扰),保证了进程独立性的特征。

4、进程和编译器均遵守进程地址空间这一套规则,编完即可使用。

编译器也遵守进程地址空间这一套规则:

我们的代码在磁盘时,程序的函数、变量等通过虚拟地址建立联系,满足程序间的互相跳转;

当程序由磁盘被加载到内存中时,就具备了物理地址。函数、变量等通过页表映射至虚拟地址。

根据可执行程序的虚拟地址初始化mm_struct结构体中每个虚拟内存中的边界。

当程序在CPU中跑起来时,CPU根据虚拟地址运行完程序后,通过页表映射至物理地址。

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...