引言
我们在前面学习 C/C++ 的过程中,关于数据在内存中的存储,大家肯定都见过这样的图片:

今天,我要告诉大家的是:实际物理内存是连续的存储单元,由操作系统内核统一管理,没有'代码段、堆、栈'这样的分区布局。这只是为进程设计的虚拟的地址空间,为什么?后面讲。
一、什么是进程地址空间?
1.1、虚拟地址
上面说的大家肯定都一头雾水,下面我们通过一段代码来让大家实际感受一下:


我们定义了一个全局变量 g_val,子进程中修改变量值,通过打印的结果,我们发现:g_val 在子进程和父进程中的地址一模一样,但结果却不同。这就说明:这里打印出来的地址一定不是物理地址,而且此时子进程和父进程各自有一个 g_val。
这个地址就是虚拟地址!!!
1.2、进程地址空间
进程地址空间也叫虚拟地址空间,其实是操作系统为每个进程分配的一个独立的、连续的虚拟内存区域。这个虚拟地址空间与物理内存并不存在一一对应的关系,而是通过内存管理单元 (MMU) 和页表机制实现动态映射。

以 32 位机器为例,这段虚拟内存区域的寻址能力为 2^32 字节(4GB),不等同于进程地址空间占 4GB 内存,其中有 1GB 为内核空间(操作系统内核运行的特权内存区域,拥有最高权限,可直接访问硬件资源和执行敏感操作(如内存管理、进程调度、设备驱动等)),剩下 3GB 为用户空间(普通应用程序运行的非特权内存区域,权限受限,无法直接访问硬件或内核资源)。
同时,用户空间又被细分为了上图所示的区域。
1.3、进程地址空间的管理
在 Linux 中,为了方便管理进程地址空间,操作系统在底层的 task_struct 内部存在着一个结构体指针,该结构体指针的类型是 mm_struct 结构体,该结构体中存在着一些变量用于存储指定区域的起始值和终止值。这些值本质也是地址值,但是这个地址并不是实际的物理内存的地址,而是通过映射后的虚拟地址。
源码如下:
struct mm_struct { /*...*/
*;
task_size;
start_code, end_code, start_data, end_data;
start_brk, brk, start_stack;
arg_start, arg_end, env_start, env_end;
}







