【Linux】第一座高山——进程地址空间

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

大家好我是沐曦希💕

文章目录

一、什么是进程地址空间

我们在学习C/C++的动态内存空间习惯把地址空间划分为几个区域:
在这里插入图片描述
但是这并不是真的的地址空间

在这里插入图片描述
在这里插入图片描述
我们发现子进程把全局变global_value修改之后子进程和父进程的值是不同的这是合理的因为进程之间具有独立性。但是这里global_value的地址居然是相同的多进程在读取同一个地址的时候怎么可能出现不同的结果呢地址相同说明这里的地址绝对不是对应物理地址也就是说曾经我们学习的语言基本的地址(指针)不是对应的物理地址!!!

这里的地址是虚拟地址(线性地址)也可以成为逻辑地址。

能打印出来的地址空间排布全部都是虚拟地址。物理地址用户一概看不到由OS统一管理OS必须负责将 虚拟地址 转化成 物理地址 。

  • 感性理解

进程会认为自己是独占系统资源的事实上并不是。

实际上操作系统会给每一个进程都创建一个独立的虚拟地址空间然后通过页表将虚拟地址空间与物理内存一一对应 (映射)我们用户只能得到虚拟地址空间中的虚拟地址当我们修改虚拟地址中的数据时操作系统会先通过页表找到对应的物理内存然后修改物理内存中的数据。

在这里插入图片描述
这就很好理解了

父进程和子进程都有自己的独立的进程地址空间且都有自己的页表结构子进程由父进程创建所以子进程的地址空间是从父进程拷贝而来刚开始的g_val经过映射指向同一个物理内存所以刚开始看到的都是100。
后来子进程修改了自己地址空间的g_val的值当操作系统通过页表映射发现g_val的值是共享的但是我们知道进程具有独立性所以操作系统为了保证进程的独立性当子进程或者父进程任何一方尝试对共享数据进行写入那么操作系统会在物理内存上重新开辟一块新的内存空间拷贝数据然后在修改映射关系不再指向老的变量在整个修改的过程中和父子进程的虚拟地址没有任何关系只是底层经过页表映射到不同的区域所以我们看到了地址是一样的但是内容却是不一样的这就是现象的由来

写时拷贝指父子进程在上述情况下任何一方尝试写入操作系统先进行数据拷贝更改页表映射然后再让进程进行修改的过程称为写时拷贝。

进程地址空间上的地址从全0到全1按照正常的方式排列所以是连续的地址所以这个地址空间也被称为线性地址对于磁盘程序内部的地址称为逻辑地址在Linux下虚拟地址到线性地址、逻辑地址是一样的但在其他地方区分比较明确。

二、进程地址空间的管理

  • OS如何管理进程地址空间

OS会为系统中的每一个进程都创建一个地址空间但是OS中同时存在很多个许多进程那么就需要创建很多给地址空间所以为了保证各个进程正常运行OS 需要对每个进程的地址空间进行管理。

而管理的本质是先描述在组织所以和管理进程一样操作系统会使用一种内核数据结构来对地址空间进行管理Linux中用于 管理地址空间的内核数据结构叫做 mm_struct操作系统会为每个进程创建一个 mm_struct 对象然后通过管理结构体对象来间接管理进程地址空间。
在这里插入图片描述
在这里插入图片描述
所以进程地址空间也是进程的属性我们可以通过进程的 task_struct 来找到/管理进程对应的地址空间。

1.区域划分和调整

进程地址空间被划分为很多个区域例如栈区、堆区、数据区、代码段。那进程地址空间是如何进行区域划分和区域调整的把一个区域的end和start进行调整和维护内存区域

struct mm_struct{
	//uint32_t:32位系统下的无符号整型
    uint32_t code_start,code_end;
    uint32_t data_start,data_end;
    uint32_t heap_start,heap_end;
    uint32_t stack_start,stack_end;
}

所谓的区域调整本质就是修改各个区域的end或start.

三、为什么存在进程地址空间

  • 进程地址空间保证了数据的安全性

每个进程都有进程地址空间所有的进程都要通过页表映射到物理内存如果进程直接访问物理内存万一进程越界非法访问、非法读写时页表就可以进行拦截而且直接访问物理内存对于账号信息是非常不安全的所以保证了内存数据的安全性。

  • 地址空间的存在可以更方便的进行进程和进程的数据代码的解耦保证了进程独立性的特征

对于进程而言都有独立的地址空间及页表通过页表映射到不同的物理内存上所以一个进程数据的改变不会影响到另一个进程保证了进程的独立性而对于上面我们所说的父进程和子进程而言子进程的地址空间从父进程拷贝页表都指向同一块物理内存但是即使此时的数据是共享的在修改数据的时候也会发生我们所说的写时拷贝保证了进程的独立性。

  • 让进程以统一的视角看待进程对应的代码和数据各个区域方便编译器也以统一的视角来进行编译代码

可执行程序被编译器编译的时候每个代码和数据在内存中已经有虚拟地址了在磁盘上称为逻辑地址也就是说地址空间对于操作系统和编译器都是遵守的。所以当程序被加载到内存成为进程后每个变量/函数都具备了物理地址。
所以我们现在有两套地址
1.标识物理内存中代码和数据的地址
2.在程序内部互相跳转的时候的虚拟地址加载完成之后代码的各个区域的地址已经知道。进程被调度时CPU拿到虚拟地址经过地址空间查页表通过映射进行访问查到物理地址往后执行。也就是CPU通过了虚拟地址——页表映射——物理地址执行。也就是在整个CPU运行过程中,CPU并没有见到物理地址用的都是虚拟地址。

四、写在最后

每个进程都有自己独立的内核数据结构和其对应的代码已经数据。

进程=内核数据结构+进程对应的代码和数据

  • 进程地址空间区域的严格划分

在这里插入图片描述
其中我们熟悉的全局数据区代码段栈区堆区以及共享区再加上一个命令行参数环境变量所占用的进程地址空间统称用户空间在32位操作系统下这部分空间占总空间的3/4即3G剩下的1G属于内核空间。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: linux

“【Linux】第一座高山——进程地址空间” 的相关文章