程序地址空间的理解
- 程序的地址空间并不是真的物理内存,只是进程的一个地址空间
- 程序的地址空间本质就是一个描述地址分配的结构体
- 程序的地址空间只是一个虚拟的地址,两个进程可能有相同的一个地址。
来段代码感受一下:
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4
5 int g_val=0;
6 int main()
7 {
8 pid_t id=fork();
9 if(id<0)
10 {
11 perror("fork");
12 return 0;
13 }
14 else if(id==0) //child
15 {
16 printf("child[%d]:%d:%p\n",getpid(),g_val,&g_val);
17 }
18 else //parent
19 {
20 printf("parent[%d]:%d:%p\n",getppid(),g_val,&g_val);
21 }
22 sleep(1);
23 return 0;
24 }
这里输出变量的值一样很好理解,可是地址竟然也一模一样!!那么两者指向同一个物理内存吗?
想知道答案,先看下面的代码~
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4
5 int g_val=0;
6 int main()
7 {
8 pid_t id=fork();
9 if(id<0)
10 {
11 perror("fork");
12 return 0;
13 }
14 else if(id==0) //child
15 {
16 g_val=100;
17 printf("child[%d]:%d:%p\n",getpid(),g_val,&g_val);
18 }
19 else //parent
20 {
21 sleep(3);
22 printf("parent[%d]:%d:%p\n",getppid(),g_val,&g_val);
23 }
24 sleep(1);
25 return 0;
26 }
从上面的代码可以看出二者其实并不是同一个物理空间,否则就不会出现不同的值。在Linux 地址下,我们把上面这种地址叫做虚拟地址,在C/C++下看到的地址也都是虚拟地址。
物理内存用户一般看不到,是由OS进行统一管理。OS负责将虚拟地址转化为物理地址(转化的方式:映射关系 即页表+MMU)
设置虚拟地址的作用
1) 让进程看起来像独占整个系统资源(方便用户理解)
举个例子:富翁有五百亿和五个私生子,他们五个私生子并不知道彼此的存在,所以他们每个人都以为自己有五百亿的资产可以继承。而现实是他们并不是每个人都有五百亿的资产,只是富翁给他们的错觉,让他们以为自己独占那么多资产。
2)让所有进程可以以同样的方式访问内存(方便进程快速访问)。
3)让软件和OS介入是为了保护物理内存不会被随意破坏。
进程地址空间
出现进程相当于 PCB+地址空间+映射关系(页表+MMU)
每个进程都有一个虚拟空间,虚拟地址必须映射到物理空间才能取到内容。
页表的简单结构:二级页表
注意: 页目录占用的资源是一定的,不过页框是通过映射得出的,所以可以节省很多资源。