?????????在我们学习C语言或C++时,都听说过内存被分为栈区、堆区、静态区、常量区、代码区,对应图如下:
?????????而这里指的内存并不是真实的物理内存,而是虚拟内存,每一个进程都有对应的虚拟内存,再通过页表与物理内存建立对应的映射,从而完成虚拟内存到物理内存的转换,这些工作都是由操作系统完成的,在每一个进程看来,它们都拥有完整的一块内存。
????????验证:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int i = 0;
pid_t id = fork();
if (id == 0)
{
i = 3;
printf("I am child process, i = %d, &i = %p\n", i, &i);
}
else
{
i = 5;
printf("I am parent process, i = %d, &i = %p\n", i, &i);
}
sleep(1);
return 0;
}
?????????当我们运行如上代码时,出现了地址相同而存的值不同的情况,由此我们可以验证,我们拿到的地址都是虚拟地址,fork之后创建了新的子进程,而新的子进程给它分配了新的一份虚拟地址,他们在各自的虚拟地址上对应到不同物理地址,修改 i?的值,就出现了上述情况。
????????内核代码:在struct task_struct也就是PCB中,存在mm_struct( 内存描写符),在mm_struct中,有一系列的start和end,这就是划分好的虚拟地址。(第一张图)
有了虚拟地址空间:?
????????a、我们可以将物理内存从无序变为有序,让进程以统一的视角看待内存;
? ? ? ? b、将进程管理与内存管理进行解耦合。?
? ? ? ? c、地址空间 + 页表能够很好的保护内存安全,在用户错误使用内存时,页表不会建立映射,而是直接报错,反馈给用户。