作者:小 琛
欢迎转载,请标明出处
我们看到的地址是真实的物理地址吗?
来看一个例子:以下代码中,父子进程同时对一个变量num进行了运算,父进程让其加,子进程让其减,随之打印其地址。
#include "stdio.h"
2 #include "unistd.h"
3 #include "sys/types.h"
4 #include "sys/wait.h"
5 int main()
6 {
7 int num=10;
8 pid_t pid=fork();
9 if (pid<0)
10 {
11 perror("fork");
12 return 0;
13 }
14 else if (pid==0)
15 {
16 //child
17 num-=10;
18 printf("i am child num=[%d],&num=[%p]\n",num,&num);
19 }
20 else if (pid>0)
21 {
//father
22 num+=10;
23 printf("i am father num=[%d],&num=[%p]\n",num,&num);
24 wait(NULL);
25 }
26 return 0;
27 }
结果如下:
这里就出现问题了!!!
变量num的值在父进程中被修改为了20,子进程中被修改为了0,但二者竟然使用的是同一个内存空间中的变量???但一个变量怎么可能拥有两种值呢?
虚拟地址空间
因此,我们通常叫的进程地址空间实际上是不合理的,因为它本质是提供给我们读的虚拟地址空间。
在内核中,创建一个进程,在内核有了它的PCB,其内存指针指向的本质是其虚拟内存,地址也必然为虚拟地址,而该虚拟地址通过页表映射关系(后续讲解)到物理内存处。
在该例子中,二者对于同一个变量操作,实际上在物理内存中已经有了两块存储地方,分别分别存放两个不同的值,但通过页表映射的虚拟逻辑地址是相同的。
页表的映射规则
- 段页式
将内存视为块分
1、根据虚拟地址得到段号,进而在段表中得到页内起始地址
2、根据刚刚得到的页内起始地址和页号得到块号
3、根据块号和页内偏移在物理内存中找到该地址