进程地址空间

举报
绝活蛋炒饭 发表于 2024/12/15 19:16:23 2024/12/15
【摘要】 关于进程地址空间的第一部分的介绍,详细介绍了进程地址空间,页表和物理地址之间的关系。深刻说明了进程地址空间和页表存在的意义。

1.引言


1.1验证地址空间的内部布局

#include<stdio.h>
    2 #include<stdlib.h>
    3    
    4 int g_val1 = 100;
    5 int g_val2;
    6 
  7 int main(int argc, char* argv[], char* env[])
    8 {
    9     printf("code adr:%p\n", main);  //正文代码
   10     printf("init data code:%p\n", &g_val1);  //初始化全局变量
   11     printf("uninit data code:%p\n", &g_val2);  //未初始化全局变量
   12 
   13     char* heap1 = (char*)malloc(10);
   14     char* heap2 = (char*)malloc(10);
   15     char* heap3 = (char*)malloc(10);
   16     char* heap4 = (char*)malloc(10);
   17 
   18     printf("stack adr:%p\n", &heap1);  //栈
   19     printf("stack adr:%p\n", &heap2);
   20     printf("stack adr:%p\n", &heap3);
   21     printf("stack adr:%p\n", &heap4);                                                                                                                             
   22 
   23     printf("heap adr:%p\n", heap1);  //堆
   24     printf("heap adr:%p\n", heap2);
   25     printf("heap adr:%p\n", heap3);
   26     printf("heap adr:%p\n", heap4);
   27 
   28     for(int i = 0; i < 2; i++)  //命令行参数表
   29     printf("命令行参数表%d adr:%p\n", i, argv + i);
   30     for(int i = 0; i < 2; i++)  //环境变量表
   31     printf("环境变量表%d adr:%p\n", i, env + i);
   32 
   33     for(int i = 0; argv[i]; i++)   //命令行参数
   34         printf("argv[%d]=%p\n", i, argv[i]);
   35     for(int i = 0; env[i]; i++)   //环境变量
   36         printf("env[%d]=%p\n", i, env[i]);
   37 
   38     return 0;
   39 }

编辑



 1.2.利用fork函数观察子进程对某个共享数据修改时父子进程读取到的值和地址


编辑

编辑

我们知道,子进程在创建的时候会和父进程共用一片代码和数据,当其中一个要修改其中的数据时会发生写时拷贝。 

但是,根据我们看到的现象,发现子进程在修改了val 的值时,地址并未发生变化,Linux可以用一个变量表示不同的值,但是肯定不能,用一块地址存下两个值。 

所以,我们得出结论:我们程序观察到的地址,不是物理意义上的地址,只是操作系统维护的虚拟地址也就是我们的地址进程空间。 

我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理。

1.3页表和虚拟地址 

编辑

进程地址空间中的地址,是维护出来让用户查看的,但是,他也一定需要和真正的物理地址联系起来,这靠什么?靠页表,让虚拟地址和物理地址对应起来,产生一对一的联系。

所以说,子进程和父进程的val值虚拟地址虽然相同,但是,由于页表上的对应关系不同,让他们指向了两个不同的物理地址,这样他们的值就产生了不同。 


2.进程地址空间 


2.1进程地址空间是怎么一回事

进程地址空间:没一个进程都会有一个进程地址空间大小[0.4GB](32位)

具体到代码部分就是,数据结构

 编辑

2.2进程地址空间内部的属性(即空间区域划分)

地址空间划分的概念:进程地址空间是特定的数据结构,主要包含的字段是对地址空间进行区域划分,在特定位数的计算机中它能寻址的地址范围中划分为若干个区域,方便了操作系统的寻址操作。

这个区域划分,就向小时候在桌子上化三八线一样,[0,30]是你的,[30.100]是我的。

编辑

Linux的代码实现也就是跟什么差不多,进行区域划分。 

编辑  

 区域划分目的:也就是为了方便管理,用特定的数字位进行划分,可以判断是否越位,是否需要扩容或者缩容。

区域划分的本质:也是为了,每一个地址都能被使用。



3.页表 


3.1概念

页表:是用于支持虚拟内存管理的数据结构;主要用于存储虚拟地址到物理地址的映射关系;使得程序能够透明地使用虚拟地址空间,而无需管理物理内存(不必关心物理内存的具体布局)。

页表将虚拟地址转化为物理地址的过程,是由CPU内部的一个硬件组件MMU(内存管理单元)来完成的。MMU能够自动完成页表的映射、查找等工作,从而实现虚拟地址到物理地址的转化,进而找到数据并将其加载到CPU中进行处理。

CR3寄存器中保存了指向当前活动页表的物理地址,当MMU需要进行地址转化时,它会使用CR3中的值来定位正确的页表结构。

进程地址空间不具备对代码和数据的保存能力,而是通过页表机制和MMU的支持,将虚拟地址空间映射到物理内存,从而实现了代码和数据的保存和访问。

编辑



3.2关于malloc()函数和new()函数跟深层次的理解 

在我们写程序的时候,使用malloc和new函数申请了空间,我们并不一定第一时间就去使用这份空间,但是呢,这份空间一直占据在哪里,让别人无法使用,自己又不用。操作系统是非常追求效率的,所以,面对这种情况,操作系统做了一些特殊处理。

一开始,用户申请空间的时候,为了防止物理内存空转,OS并不会分配物理空间,只会分配一块虚拟地址空间,然后这块虚拟地址空间在页表上是没有对应关系的。 

那么什么时候分配物理空间呢?只有用户真正的要用到这个空间的时候,才分配。即用户要对这片空间进行写时拷贝的时候。 (延时分配效率)

这样就能够保证了OS的效率,防止内存空间的浪费。 

用户在OS上使用malloc或者new函数要经过的几个步骤:

申请空间 -> 虚拟内存分配 -> 尝试写入 ->缺页中断 ->  物理内存的分配 -> 页表映射 -> 写入操作。 



3.3 缺页中断

当用户尝试向虚拟地址进行写入,OS就会发现当前是往合理的空间内进行写入,且页表中当前并未建立虚拟地址到物理地址的映射关系,就会触发 “缺页中断”,将写入操作暂停,开辟物理内存,再建立对应的映射关系,一旦页表映射建立完成,用户就可以进行写入操作 


3.4写时拷贝的原理 

写时拷贝的过程:代码程序共享阶段 -> 尝试写入数据 -> 缺页中断 ->建立映射关系和分配物理地址-> 权限更新

 编辑

页表上其实还有存储着权限位这个信息,当子进程创建的时候,继承父进程的数据和可执行程序时,父子进程在页表上记录着的,对于内存上的代码和数据都只有可读权限,当其中一方想要去修改数据时,发生写时拷贝的时候,就必然改动权限。 

权限更新包括以下内容:

原页面权限:可读(保持不变)。这确保了其他进程不能通过这条路径改变数据,从而维护了数据的一致性。

新页面限:标记为可读写(rw),供请求写入的进程自由使用。


4.进程地址空间和页表存在的意义


4.1.将物理内存从无序变为有序,让进程以统一的视角,看待内存。

统一的视角:每个进程都有进程地址空间,这个空间是个连续的线性地址空间。意味着每个进程看到的内存布局时一样的,无论内存是如何分布,进程统一认为自己拥有一个完整的、连续的线性地址空间。

无序变为有序:通过进程地址空间和页表机制,即使物理内存是分散的,可以通过页表将它们映射成连续的虚拟地址空间。

 4.2将进程管理和内存管理进行解耦合。

解耦合:页表的存在使得操作系统将进程管理和内存管理进行分离。进程管理模块主要负责创建、调度和终止进程,内存管理模块主要负责物理内存的申请和释放。通过页表,进程可以被加载到磁盘的任意位置,而不需要关心具体的内存布局。


 4.3保护内存空间

内存保护:页表提供了内存保护机制,可以设置权限来控制不同内存区域的访问权限,如:有些区域只能特定的进程访问、有些区域只能读不能写等。

保护内存安全,对异常地址的访问时,它们就会拦住非法的请求操作。eg:访问野指针,程序崩溃,但并不影响OS正常的运行,也不影响其他进程正常运行,因为拦住你的是你自己的地址空间和页表,只会影响你自己。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。