目录
1. 验证程序地址空间布局图
2. 虚拟地址空间
什么是虚拟地址空间
3. 进程地址空间
4. 为什么要有虚拟地址空间
1. 有效保护物理内存
2. 使内存管理模块和进程管理模块实现解耦合
3. 将内存分布有序化
1. 验证程序地址空间布局图
下面我们写段代码验证一下上图中的各数据地址什么从低到高,以及堆栈地址相对增长:
运行验证:
根据运行结果,我们可以知道我们的布局图是正确的!
2. 虚拟地址空间
先演示一段代码看结果:
从结果上可以发现:父进程,子进程的 g_val 的地址相同,值却不同,这不是很矛盾吗?
我们从中得出以下结论:
- 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量
- 但地址值是一样的,说明,该地址绝对不是物理内存地址!
- 在Linux地址下,这种地址叫做 虚拟地址(线性地址).
- 我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理。OS必须负责将 虚拟地址 转化成 物理地址 。
什么是虚拟地址空间
地址空间是一种内核数据结构,它里面至少要有:各个区域的划分:
每个进程都会创建一个独属于自己的虚拟地址空间和页表,页表将虚拟地址与物理内存地址建立联系(映射关系),只要保证每一个进程的页表映射的是物理内存的不同区域,就能做到进程间互不干扰,实现进程的独立性。
3. 进程地址空间
现在,我们就可以根据这张图很好的解释第2点演示代码中 g_val 地址相同值却不同的原因了。
解释:子进程以父进程为模板,所以子进程内虚拟地址空间的 g_val 的虚拟地址是一样的,映射在物理内存中的位置也一样,但是!当子进程修改g_val值时,会发生写时拷贝,即子进程修改g_val值时,页表会把物理内存中g_val的地址映射到不同于父进程中g_val地址的新地址(如上图所示),因此,演示代码中g_val地址相同是指虚拟地址相同,值不同其实是因为被映射到了不同的物理地址!
4. 为什么要有虚拟地址空间
1. 有效保护物理内存
因为地址空间和页表是OS创建并维护的,也就意味着想使用地址空间好页表进行映射就必须在OS监管下进行,当有非法访问或者映射时,OS会识别并终止这个进程,这样就很好的保护了物理内存中所有的合法数据,包括各个进程,以及内核的相关有效数据。
2. 使内存管理模块和进程管理模块实现解耦合
因为有地址空间和页表的映射关系存在,在物理内存中,我们可以对未来的数据进行任意位置的加载!物理内存的分配和进程的管理就可以做到没有关系!从而实现 进程管理模块 和 内存管理模块的解耦合。
Tip:
实际上,因为有地址空间的存在,所以上层用户申请空间,实际上是申请地址空间,物理内存甚至可以一个字节都不分配!而当你真正对物理内存进行访问的时候,OS才会执行内存的相关管理算法,帮你申请内存,构建页表映射关系,然后才让你进行内存的访问。这种延时分配的策略,可以提高整机的效率,使内存的有效使用几乎是100%的!
3. 将内存分布有序化
因为在物理内存中理论上可以在任意位置进行加载,因此物理内存中几乎所有的数据和代码在物理内存中都是乱序的。但是!因为页表的存在,可以将地址空间上的虚拟地址和物理地址进行映射,那么在进程视角,所有的内存分布,都可以是有序的!