文章目录
C语言地址空间回顾
我们在讲C语言的时候,老师给大家画过这样的空间布局图
 
C/C++内存分布简图:
+------------------+     高地址
|                  |
|       栈         | <- 本地变量,函数调用信息等
|                  |
+------------------+
|                  |
|       堆         | <- 动态分配的变量(malloc/new)
|                  |
+------------------+
|                  |
|   未初始化数据段   |
|    (BSS 段)     | <- 未初始化的静态和全局变量
|                  |
+------------------+
|                  |
|   已初始化数据段    | <- 已初始化的静态和全局变量
|     (数据段)      |
|                  |
+------------------+
|                  |
|    常量数据段      | <- 字面量,常量字符串等
|                  |
+------------------+
|                  |
|      代码段       | <- 程序代码(虚函数和普通函数)
|                  |
+------------------+     低地址
 
 
 
进程地址空间概念
实际上操作系统会给每一个进程都创建一个独立的虚拟地址空间,然后通过页表将虚拟地址空间与物理内存一一对应 (映射),我们用户只能得到虚拟地址空间中的虚拟地址,当我们修改虚拟地址中的数据时,操作系统会先通过页表找到对应的物理内存,然后修改物理内存中的数据。
 
Linux是如何管理每个进程的地址空间?
所以,和管理进程一样,操作系统会使用一种内核数据结构来对地址空间进行管理,Linux中用于 管理地址空间的内核数据结构叫做 mm_struct,操作系统会为每个进程创建一个 mm_struct 对象,然后通过管理结构体对象来间接管理进程地址空间。
 
查看mm_struct的定义:
struct mm_struct 
{
	// ...
    unsigned long total_vm, locked_vm, shared_vm, exec_vm;
    unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;
    unsigned long start_code, end_code, start_data, end_data;
    unsigned long start_brk, brk, start_stack;
    unsigned long arg_start, arg_end, env_start, env_end;
    // ...
};
 
total_vm:可能表示虚拟内存的总量。locked_vm:可能表示被锁定,不能被换出的虚拟内存的数量。shared_vm:可能表示被多个进程共享的虚拟内存的数量。exec_vm:可能表示可执行的虚拟内存的数量。stack_vm:可能表示栈内存的虚拟内存的数量。reserved_vm:可能表示已预留但尚未使用的虚拟内存的数量。def_flags:可能表示默认的内存区域标志。nr_ptes:可能表示页表条目的数量。start_code,end_code:可能表示代码段的开始和结束位置。start_data,end_data:可能表示数据段的开始和结束位置。start_brk,brk:可能表示堆的开始位置和当前位置。start_stack:可能表示栈的开始位置。arg_start,arg_end:可能表示命令行参数的开始和结束位置。env_start,env_end:可能表示环境变量的开始和结束位置。
可以看到,进程地址空间其实也是进程属性的一种,我们可以通过进程的 task_struct 来找到/管理进程对应的地址空间。
为什么要有进程地址空间和页表?
- 因为有了进程地址空间和页表,物理内存空间上不连续、无序的空间就可以通过页表这一映射关系联系在一起,让进程以统一的视角看待内存。
 - 有了进程地址空间和页表后,每个进程都认为自己在独占内存,这样能更好的保障进程的独立性以及合理使用内存空间(当实际需要使用内存空间的时候再在内存进行开辟),并能将进程管理与内存管理进行解耦合。
 - 地址空间+页表的设计是保护内存安全的重要手段!
 
页表的细节
页表其实不光存放虚拟地址和物理内存地址,还有其他的属性,比如会存放权限属性。
 










