一、何为进程地址空间
在我们学习C语言C++的时候,我们知道内存被划分为堆区,栈区,常量区等等,事实上这里的内存并不是物理内存,而是一个虚拟的内存空间,我们写代码时能访问得到的只有虚拟内存,系统再通过一种映射关系在物理内存上执行对应的操作,通过禁止用户直接访问物理内存从而避免因操作不当而引发事故。在Linux中,当你的程序跑起来就变成了一个进程,它的代码和数据需加载到内存,所访问到的虚拟内存就叫做进程地址空间(mm_struct)
二、为什么要有进程地址空间
- 从此之后再也不会有系统级别(指访问物理内存)的越界问题了,因为虚拟内存阶段在映射的时候会检查,不会出现越界访问物理内存的情况
- 每个进程的进程地址空间布局,范围都一致,使得对每个进程的操作,设计都一致,这样就不用不同的进程不同的"分析"了
- 每个进程都认为自己独占内存,这样能更好地保持进程独立性以及合理使用空间
- 进程管理和内存管理完成解耦
三、深入探究进程地址空间
进程地址空间本质是内存中的一种内核数据结构——mm_struct,通过结构体:定义很多变量规定栈区,堆区等等区域的起始终止位置,而这个结构体最多有2^32个寻址地址,如:
struct mm_struct{
unsigned int heap_start; //规定堆区的开始地址
unsigned int heap_end; //规定堆区的结束地址
unsigned int code_start; //规定代码区的开始地址
unsigned int code_end; //规定代码区的结束地址
……
}
从start到end则是一段虚拟区域,这区域之间每一个寻址地址是虚拟地址
当操作系统创建一个进程后,会将代码和数据从硬盘加载到内存,创建task_struct存储进程相关信息来控制和管理进程,同时创建mm_struct(进程地址空间)为了让进程访问内存,上文说到进程地址空间会通过一种映射关系映射到物理内存上,这个映射关系存储在页表中,每一个进程的task_struct和mm_struct通过指针链接在一起。对于创建子进程,也为其创建mm_struct和task_struct,将代码和数据加载到内存,虚拟地址和页表父进程一样,在写入的时候进行写时拷贝